diff --git a/.bumpversion.cfg b/.bumpversion.cfg new file mode 100644 index 000000000..ac1d31324 --- /dev/null +++ b/.bumpversion.cfg @@ -0,0 +1,29 @@ +[bumpversion] +current_version = 2.4.0.dev0 +parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\.(?P[a-z]+)(?P\d+))? +serialize = + {major}.{minor}.{patch}.{release}{dev} + {major}.{minor}.{patch} + +[bumpversion:part:release] +optional_value = dummy +values = + dev + dummy + +[bumpversion:part:dev] + +[bumpversion:file:setup.py] + +[bumpversion:file:conda.recipe/meta.yaml] + +[bumpversion:file:src/runtime/resources/clr.py] + +[bumpversion:file:src/SharedAssemblyInfo.cs] +serialize = + {major}.{minor}.{patch} + +[bumpversion:file:src/clrmodule/ClrModule.cs] +serialize = + {major}.{minor}.{patch} + diff --git a/.editorconfig b/.editorconfig index ff0b3c71d..2e7c58ffe 100644 --- a/.editorconfig +++ b/.editorconfig @@ -16,9 +16,14 @@ trim_trailing_whitespace = true indent_size = 2 # Xml project files -[*.{csproj,config,build,config}] +[*.{csproj,pyproj,config}] indent_size = 2 # Solution [*.sln] indent_style = tab + +# bumpversion reformats itself after every bump +[.bumpversion.cfg] +trim_trailing_whitespace = false +indent_style = tab diff --git a/.gitignore b/.gitignore index 968a5c66a..6f813dcb0 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,6 @@ _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm + +# Coverity +cov-int/ diff --git a/.mention-bot b/.mention-bot new file mode 100644 index 000000000..f07fa548e --- /dev/null +++ b/.mention-bot @@ -0,0 +1,35 @@ +{ + "maxReviewers": 5, + "numFilesToCheck": 10, + "message": "@pullRequester, thanks! @reviewers, please review this.", + "alwaysNotifyForPaths": [ + { + "name": "ghuser", + "files": ["src/js/**/*.js"], + "skipTeamPrs": false + } + ], + "fallbackNotifyForPaths": [ + { + "name": "ghuser", + "files": ["src/js/**/*.js"], + "skipTeamPrs": false + } + ], + "findPotentialReviewers": true, + "fileBlacklist": ["*.md"], + "userBlacklist": [], + "userBlacklistForPR": [], + "requiredOrgs": [], + "actions": ["opened"], + "skipAlreadyAssignedPR": false, + "skipAlreadyMentionedPR": false, + "assignToReviewer": false, + "createReviewRequest": false, + "createComment": true, + "skipTitle": "", + "withLabel": "", + "delayed": false, + "delayedUntil": "3d", + "skipCollaboratorPR": false +} diff --git a/.travis.yml b/.travis.yml index b24531f93..025229d04 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,31 +1,114 @@ -sudo: required +dist: trusty +sudo: false language: python + +matrix: + include: +# --------------------- XPLAT builds ------------------------ + - python: 2.7 + env: &xplat-env + - BUILD_OPTS=--xplat + - NUNIT_PATH=~/.nuget/packages/nunit.consolerunner/3.*/tools/nunit3-console.exe + addons: &xplat-addons + apt: + sources: + - sourceline: deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-trusty-prod trusty main + key_url: https://packages.microsoft.com/keys/microsoft.asc + - sourceline: deb http://download.mono-project.com/repo/ubuntu trusty main + key_url: http://keyserver.ubuntu.com/pks/lookup?op=get&search=0xA6A19B38D3D831EF + packages: + - mono-devel + - ca-certificates-mono + - dotnet-hostfxr-2.0.0 + - dotnet-runtime-2.0.0 + - dotnet-sdk-2.0.0 + - python: 3.3 + env: *xplat-env + addons: *xplat-addons -python: - - 2.7 - - 3.3 - - 3.4 - - 3.5 - - 3.6 + - python: 3.4 + env: *xplat-env + addons: *xplat-addons + + - python: 3.5 + env: *xplat-env + addons: *xplat-addons + + - python: 3.6 + env: *xplat-env + addons: *xplat-addons + - python: "3.7-dev" + env: *xplat-env + addons: *xplat-addons + +# --------------------- Classic builds ------------------------ + - python: 2.7 + env: &classic-env + - BUILD_OPTS= + - NUNIT_PATH=./packages/NUnit.*/tools/nunit3-console.exe + + - python: 3.3 + env: *classic-env + + - python: 3.4 + env: *classic-env + + - python: 3.5 + env: *classic-env + + - python: 3.6 + env: *classic-env + + - python: "3.7-dev" + env: *classic-env + + allow_failures: + - python: "3.7-dev" + env: *xplat-env + + - python: "3.7-dev" + env: *classic-env + +env: + global: + - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so + - SEGFAULT_SIGNALS=all + - PYTHONUNBUFFERED=True + - CODECOV_ENV=TRAVIS_PYTHON_VERSION + +addons: + apt: + sources: + - sourceline: deb http://download.mono-project.com/repo/ubuntu trusty main + key_url: http://keyserver.ubuntu.com/pks/lookup?op=get&search=0xA6A19B38D3D831EF + packages: + - mono-devel + - ca-certificates-mono before_install: - - sudo add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu/ trusty main universe" - - sudo apt-get install software-properties-common - - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF - - echo "deb http://download.mono-project.com/repo/debian wheezy/snapshots/4.2.4.4 main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list - - echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list - - sudo apt-get update - - sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confnew" install mono-devel mono-complete referenceassemblies-pcl ca-certificates-mono nunit-console + # Set-up dll path for embedded tests + - PY_LIBDIR=$(python -c 'import sysconfig; print(sysconfig.get_config_var("LIBDIR"))') + - export LD_LIBRARY_PATH=$PY_LIBDIR:$LD_LIBRARY_PATH install: - - pip install six - - pip install pycparser - - python setup.py build_ext --inplace + - pip install --upgrade setuptools # TEMP - due to setuptools 36.2.0 bug + - pip install --upgrade -r requirements.txt + - coverage run setup.py install $BUILD_OPTS script: - - export PYTHONPATH=`pwd`:$PYTHONPATH - - python src/tests/runtests.py - # - nunit-console src/embed_tests/bin/x64/ReleaseMono/Python.EmbeddingTest.dll + - python -m pytest + - mono $NUNIT_PATH src/embed_tests/bin/Python.EmbeddingTest.dll + - if [[ $BUILD_OPTS == --xplat ]]; then dotnet src/embed_tests/bin/netcoreapp2.0_publish/Python.EmbeddingTest.dll; fi + +after_script: + # Uncomment if need to geninterop, ie. py37 final + # - python tools/geninterop/geninterop.py + + # Waiting on mono-coverage, SharpCover or xr.Baboon + - coverage xml -i + - codecov --file coverage.xml --flags setup_linux notifications: email: false + slack: + secure: "UiQdSK1/uNnHl8/gQgfLj/F5JGxtJuaT3QYtKNcw3Ddpr3FX8tfXJ/RjsCsSlRQzDm7AdBAeMzcBQmvH4iRIV2y7qVywLyru5MPiwY4ZjMN6fJK/zaaxetOct9fasIBYzHguNPDAtiBGFh2iK1H1MXTY8rkmU3WZvl18b8EsrP0=" diff --git a/AUTHORS.md b/AUTHORS.md index 2a2110f26..55aa69d11 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -12,30 +12,40 @@ ## Contributors +- Arvid JB ([@ArvidJB](https://github.com/ArvidJB)) - Bradley Friedman ([@leith-bartrich](https://github.com/leith-bartrich)) +- Callum Noble ([@callumnoble](https://github.com/callumnoble)) - Christian Heimes ([@tiran](https://github.com/tiran)) - Christoph Gohlke ([@cgohlke](https://github.com/cgohlke)) +- Christopher Pow ([@christopherpow](https://github.com/christopherpow)) +- Daniel Fernandez ([@fdanny](https://github.com/fdanny)) - Daniel Santana ([@dgsantana](https://github.com/dgsantana)) +- Dave Hirschfeld ([@dhirschfeld](https://github.com/dhirschfeld)) - David Lechner ([@dlech](https://github.com/dlech)) +- Dmitriy Se ([@dmitriyse](https://github.com/dmitriyse)) - He-chien Tsai ([@t3476](https://github.com/t3476)) -- Jeff Reback ([@jreback](https://github.com/jreback)) +-   Ivan Cronyn ([@cronan](https://github.com/cronan)) +-   Jeff Reback ([@jreback](https://github.com/jreback)) - Joe Frayne ([@jfrayne](https://github.com/jfrayne)) - John Burnett ([@johnburnett](https://github.com/johnburnett)) - Luke Stratman ([@lstratman](https://github.com/lstratman)) +- Konstantin Posudevskiy ([@konstantin-posudevskiy](https://github.com/konstantin-posudevskiy)) - Matthias Dittrich ([@matthid](https://github.com/matthid)) - Patrick Stewart ([@patstew](https://github.com/patstew)) - Raphael Nestler ([@rnestler](https://github.com/rnestler)) +- Rickard Holmberg ([@rickardraysearch](https://github.com/rickardraysearch)) - Sam Winstanley ([@swinstanley](https://github.com/swinstanley)) - Sean Freitag ([@cowboygneox](https://github.com/cowboygneox)) - Serge Weinstock ([@sweinst](https://github.com/sweinst)) +- Ville M. Vainio ([@vivainio](https://github.com/vivainio)) - Virgil Dupras ([@hsoft](https://github.com/hsoft)) +- Wenguang Yang ([@yagweb](https://github.com/yagweb)) - Xavier Dupré ([@sdpython](https://github.com/sdpython)) - Zane Purvis ([@zanedp](https://github.com/zanedp)) -- ([@ArvidJB](https://github.com/ArvidJB)) - ([@bltribble](https://github.com/bltribble)) -- ([@dmitriyse](https://github.com/dmitriyse)) -- ([@fdanny](https://github.com/fdanny)) - ([@omnicognate](https://github.com/omnicognate)) - ([@rico-chet](https://github.com/rico-chet)) - ([@rmadsen-ks](https://github.com/rmadsen-ks)) - ([@stonebig](https://github.com/stonebig)) +- ([@testrunner123](https://github.com/testrunner123)) + diff --git a/CHANGELOG.md b/CHANGELOG.md index 4515cde20..96461ca68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,97 @@ This project adheres to [Semantic Versioning][]. This document follows the conventions laid out in [Keep a CHANGELOG][]. +## [unreleased][] + +### Added +- Added support for embedding python into dotnet core 2.0 (NetStandard 2.0) +- Added new build system (pythonnet.15.sln) based on dotnetcore-sdk/xplat(crossplatform msbuild). + Currently there two side-by-side build systems that produces the same output (net40) from the same sources. + After a some transition time, current (mono/ msbuild 14.0) build system will be removed. +- NUnit upgraded to 3.7 (eliminates travis-ci random bug) +- Added `clr.GetClrType` (#432, #433) +- Allowed passing `None` for nullable args (#460) +- Added keyword arguments based on C# syntax for calling CPython methods (#461) + +### Changed + +### Fixed + +- Fixed Visual Studio 2017 compat (#434) for setup.py +- Fixed crash on exit of the Python interpreter if a python class + derived from a .NET class has a `__namespace__` or `__assembly__` + attribute (#481) +- Fixed conversion of 'float' and 'double' values (#486) +- Fixed 'clrmethod' for python 2 (#492) +- Fixed double calling of constructor when deriving from .NET class (#495) +- Fixed `clr.GetClrType` when iterating over `System` members (#607) +- Fixed `LockRecursionException` when loading assemblies (#627) +- Fixed errors breaking .NET Remoting on method invoke (#276) + + +## [2.3.0][] - 2017-03-11 + +### Added + +- Added Code Coverage (#345) +- Added `PySys_SetArgvEx` (#347) +- Added XML Documentation (#349) +- Added `Embedded_Tests` on AppVeyor (#224)(#353) +- Added `Embedded_Tests` on Travis (#224)(#391) +- Added PY3 settings to solution configuration-manager (#346) +- Added `Slack` (#384)(#383)(#386) +- Added function of passing an arbitrary .NET object as the value + of an attribute of `PyObject` (#370)(#373) +- Added `Coverity scan` (#390) +- Added `bumpversion` for version control (#319)(#398) +- Added `tox` for local testing (#345) +- Added `requirements.txt` +- Added to `PythonEngine` methods `Eval` and `Exec` (#389) +- Added implementations of `ICustomMarshal` (#407) +- Added docker images (#322) +- Added hooks in `pyinstaller` and `cx_freeze` for `pythonnet` (#66) + +### Changed + +- Refactored python `unittests` (#329) +- Refactored python `setup.py` (#337) +- Refactored remaining of Build Directives on `runtime.cs` (#339) +- Refactored `Embedded_Tests` to make easier to write tests (#369) +- Changed `unittests` to `pytest` (#368) +- Upgraded NUnit framework from `2.6.3` to `3.5.0` (#341) +- Downgraded NUnit framework from `3.5.0` to `2.6.4` (#353) +- Upgraded NUnit framework from `2.6.4` to `3.6.0` (#371) +- Unfroze Mono version on Travis (#345) +- Changed `conda.recipe` build to only pull-requests (#345) +- Combine `Py_DEBUG` and `PYTHON_WITH_PYDEBUG` flags (#362) + +### Deprecated + +- Deprecated `RunString` (#401) + +### Fixed + +- Fixed crash during Initialization (#262)(#343) +- Fixed crash during Shutdown (#365) +- Fixed multiple build warnings +- Fixed method signature match for Object Type (#203)(#377) +- Fixed outdated version number in AssemblyInfo (#398) +- Fixed wrong version number in `conda.recipe` (#398) +- Fixed fixture location for Python tests and `Embedded_Tests` +- Fixed `PythonException` crash during Shutdown (#400) +- Fixed `AppDomain` unload during GC (#397)(#400) +- Fixed `Py_Main` & `PySys_SetArgvEx` `no mem error` on `UCS4/PY3` (#399) +- Fixed `Python.Runtime.dll.config` on macOS (#120) +- Fixed crash on `PythonEngine.Version` (#413) +- Fixed `PythonEngine.PythonPath` issues (#179)(#414)(#415) + +### Removed + +- Removed `six` dependency for `unittests` (#329) +- Removed `Mono.Unix` dependency for `UCS4` (#360) +- Removed need for `Python.Runtime.dll.config` +- Removed PY32 build option `PYTHON_WITH_WIDE_UNICODE` (#417) + ## [2.2.2][] - 2017-01-29 ### Fixed @@ -13,7 +104,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. ## [2.2.1][] - 2017-01-26 -`v2.2.0` had a release issue on pypi. Bumped to `v2.2.1` +- `v2.2.0` had a release issue on PyPi. Bumped to `v2.2.1` ### Added @@ -79,7 +170,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. ## [2.0.0][] - 2015-06-26 - Release +- Release ## 2.0.0-alpha.2 @@ -480,7 +571,9 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. [semantic versioning]: http://semver.org/ -[unreleased]: ../../compare/v2.2.2...HEAD +[unreleased]: ../../compare/v2.3.0...HEAD + +[2.3.0]: ../../compare/v2.2.2...v2.3.0 [2.2.2]: ../../compare/v2.2.1...v2.2.2 diff --git a/LICENSE b/LICENSE index 0535829ff..e344a0795 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 the contributors of the "Python for .NET" project +Copyright (c) 2006-2017 the contributors of the "Python for .NET" project Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/NuGet.config b/NuGet.config new file mode 100644 index 000000000..719fbc83c --- /dev/null +++ b/NuGet.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Python.Runtime.dll.config b/Python.Runtime.dll.config deleted file mode 100644 index 228c1417a..000000000 --- a/Python.Runtime.dll.config +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - diff --git a/README.md b/README.md index 0b6abe756..7e859481d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,17 @@ # pythonnet - Python for .NET +[![Join the chat at https://gitter.im/pythonnet/pythonnet](https://badges.gitter.im/pythonnet/pythonnet.svg)](https://gitter.im/pythonnet/pythonnet?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + [![appveyor shield][]](https://ci.appveyor.com/project/pythonnet/pythonnet/branch/master) [![travis shield][]](https://travis-ci.org/pythonnet/pythonnet) +[![codecov shield][]](https://codecov.io/github/pythonnet/pythonnet) +[![coverity shield][]](https://scan.coverity.com/projects/pythonnet) + [![license shield][]](./LICENSE) [![pypi package version][]](https://pypi.python.org/pypi/pythonnet) [![python supported shield][]](https://pypi.python.org/pypi/pythonnet) +[![stackexchange shield][]](http://stackoverflow.com/questions/tagged/python.net) +[![slack][]](https://pythonnet.slack.com) Python for .NET is a package that gives Python programmers nearly seamless integration with the .NET Common Language Runtime (CLR) and @@ -34,14 +41,14 @@ from System.Windows.Forms import Form ## Embedding Python in .NET - All calls to python should be inside - a `using (Py.GIL()) {/_ Your code here _/}` block. + a `using (Py.GIL()) {/* Your code here */}` block. - Import python modules using `dynamic mod = Py.Import("mod")`, then you can call functions as normal, eg `mod.func(args)`. -- Use `mod.func(args, Py.kw("keywordargname", keywordargvalue))` +- Use `mod.func(args, Py.kw("keywordargname", keywordargvalue))` or `mod.func(args, keywordargname: keywordargvalue)` to apply keyword arguments. - All python objects should be declared as `dynamic` type. - Mathematical operations involving python and literal/managed types must - have the python object first, eg `np.pi_2` works, `2_np.pi` doesn't. + have the python object first, eg. `np.pi * 2` works, `2 * np.pi` doesn't. ### Example @@ -51,17 +58,21 @@ static void Main(string[] args) using (Py.GIL()) { dynamic np = Py.Import("numpy"); + Console.WriteLine(np.cos(np.pi * 2)); + dynamic sin = np.sin; - Console.WriteLine(np.cos(np.pi*2)); Console.WriteLine(sin(5)); + double c = np.cos(5) + sin(5); Console.WriteLine(c); - /* this block is temporarily disabled due to regression + dynamic a = np.array(new List { 1, 2, 3 }); - dynamic b = np.array(new List { 6, 5, 4 }, Py.kw("dtype", np.int32)); Console.WriteLine(a.dtype); + + dynamic b = np.array(new List { 6, 5, 4 }, dtype: np.int32); Console.WriteLine(b.dtype); - Console.WriteLine(a * b); */ + + Console.WriteLine(a * b); Console.ReadKey(); } } @@ -75,15 +86,27 @@ Output: -0.6752620892 float64 int32 -[6. 10. 12.] +[ 6. 10. 12.] ``` +Information on installation, FAQ, troubleshooting, debugging, and projects using pythonnet can be found in the Wiki: + +https://github.com/pythonnet/pythonnet/wiki + [appveyor shield]: https://img.shields.io/appveyor/ci/pythonnet/pythonnet/master.svg?label=AppVeyor -[license shield]: https://img.shields.io/badge/license-MIT-blue.svg +[codecov shield]: https://img.shields.io/codecov/c/github/pythonnet/pythonnet/master.svg?label=Codecov + +[coverity shield]: https://img.shields.io/coverity/scan/7830.svg + +[license shield]: https://img.shields.io/badge/license-MIT-blue.svg?maxAge=3600 [pypi package version]: https://img.shields.io/pypi/v/pythonnet.svg [python supported shield]: https://img.shields.io/pypi/pyversions/pythonnet.svg +[slack]: https://img.shields.io/badge/chat-slack-color.svg?style=social + +[stackexchange shield]: https://img.shields.io/badge/StackOverflow-python.net-blue.svg + [travis shield]: https://img.shields.io/travis/pythonnet/pythonnet/master.svg?label=Travis diff --git a/appveyor.yml b/appveyor.yml index 2b0408bf9..8178f173f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,65 +1,75 @@ version: '{branch}-{build}' +build: off +image: + - Visual Studio 2017 + platform: - x86 - x64 environment: global: - PYTHONPATH: "C:\\testdir" - PYTHONWARNINGS: "ignore:::wheel.pep425tags:" - CONDA_BLD_VERSION: "3.5" - CONDA_BLD: "C:\\conda" - NUNIT: "nunit-console" - - # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the - # /E:ON and /V:ON options are not enabled in the batch script interpreter - # See: http://stackoverflow.com/a/13751649/163740 - CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\ci\\run_with_env.cmd" + PYTHONUNBUFFERED: True + PYTHONWARNINGS: 'ignore:::wheel.pep425tags:' + CODECOV_ENV: PYTHON_VERSION, PLATFORM matrix: - - PYTHON_VERSION: "2.7" - - PYTHON_VERSION: "3.3" - - PYTHON_VERSION: "3.4" - - PYTHON_VERSION: "3.5" - - PYTHON_VERSION: "3.6" + - PYTHON_VERSION: 2.7 + BUILD_OPTS: --xplat + - PYTHON_VERSION: 3.3 + BUILD_OPTS: --xplat + - PYTHON_VERSION: 3.4 + BUILD_OPTS: --xplat + - PYTHON_VERSION: 3.5 + BUILD_OPTS: --xplat + - PYTHON_VERSION: 3.6 + BUILD_OPTS: --xplat + - PYTHON_VERSION: 2.7 + - PYTHON_VERSION: 3.3 + - PYTHON_VERSION: 3.4 + - PYTHON_VERSION: 3.5 + - PYTHON_VERSION: 3.6 init: - # Prepare environment - - mkdir C:\testdir + # Update Environment Variables based on matrix/platform + - set PY_VER=%PYTHON_VERSION:.=% + - set PYTHON=C:\PYTHON%PY_VER% + - if %PLATFORM%==x64 (set PYTHON=%PYTHON%-x64) - # Set environment variables depending based on build cfg - - SET CONDA_PY=%PYTHON_VERSION:.=% - - SET CONDA_BLD_ARCH=%PLATFORM:x=% - - SET PYTHON=C:\PYTHON%CONDA_PY% - - IF %PLATFORM%==x86 (SET CONDA_BLD_ARCH=32) - - IF %PLATFORM%==x86 (SET NUNIT=%NUNIT%-x86) - - IF %PLATFORM%==x64 (SET PYTHON=%PYTHON%-x64) + # Put desired Python version first in PATH + - set PATH=%PYTHON%;%PYTHON%\Scripts;%PATH% install: - # install conda and deps - - ps: .\ci\install_miniconda.ps1 + - pip install --upgrade -r requirements.txt --quiet - # install for wheels - - "%PYTHON%\\python.exe -m pip install --upgrade pip" - - "%PYTHON%\\python.exe -m pip install wheel" - - "%PYTHON%\\python.exe -m pip install six" + # Install OpenCover. Can't put on `packages.config`, not Mono compatible + - .\tools\nuget\nuget.exe install OpenCover -OutputDirectory packages -Verbosity quiet build_script: - # build clean sdist & wheel - - "%PYTHON%\\python.exe setup.py sdist bdist_wheel" - - # build and dist conda package - - cmd: "%CMD_IN_ENV% %CONDA_BLD%\\Scripts\\conda build conda.recipe" - - ps: $CONDA_PKG=(& "$env:CONDA_BLD\\Scripts\\conda" build conda.recipe --output -q) - - ps: copy-item $CONDA_PKG "$env:APPVEYOR_BUILD_FOLDER\\dist\\" + # Create clean `sdist`. Only used for releases + - python setup.py --quiet sdist + # Build `wheel` with coverage of `setup.py` + - coverage run setup.py bdist_wheel %BUILD_OPTS% test_script: - - ps: '& "$env:PYTHON\\Scripts\\pip.exe" install --no-cache-dir --force-reinstall --ignore-installed ("dist\\" + (gci dist\*.whl)[0].Name)' - - ps: copy-item (gci -path build -re -include Python.Test.dll)[0].FullName C:\testdir - - "%PYTHON%\\python.exe src\\tests\\runtests.py" - # - "%NUNIT% src/embed_tests/bin/%PLATFORM%/ReleaseWin/Python.EmbeddingTest.dll" + - pip install --no-index --find-links=.\dist\ pythonnet + - ps: .\ci\appveyor_run_tests.ps1 + - ps: .\ci\appveyor_build_recipe.ps1 + +on_finish: + # Temporary disable multiple upload due to codecov limit of 20 per commit. + # https://docs.codecov.io/blog/week-8-2017 + - coverage xml -i + # - codecov --file coverage.xml --flags setup_windows + # - codecov --file py.coverage --flags python_tests + # - codecov --file cs.coverage --flags embedded_tests + - codecov --file py.coverage cs.coverage coverage.xml --flags setup_windows artifacts: - # bdist_wheel puts your built wheel in the dist directory - path: dist\* + +notifications: + - provider: Slack + incoming_webhook: + secure: 2S/t6rGHdbwoxehnvn5KgfsHrBFEtwnPD7M5olGErmz70oWFVpqoWd/EvDwh7rKZGdOTjDmpwcukc2xi5VRaGHbBAqFYS3tAdgAMrcaTNWs= diff --git a/ci/appveyor_build_recipe.ps1 b/ci/appveyor_build_recipe.ps1 new file mode 100644 index 000000000..84e0bc7c6 --- /dev/null +++ b/ci/appveyor_build_recipe.ps1 @@ -0,0 +1,39 @@ +# Build `conda.recipe` only if this is a Pull_Request. Saves time for CI. + +$env:CONDA_PY = "$env:PY_VER" +# Use pre-installed miniconda. Note that location differs if 64bit +$env:CONDA_BLD = "C:\miniconda36" + +if ($env:PLATFORM -eq "x86"){ + $env:CONDA_BLD_ARCH=32 +} else { + $env:CONDA_BLD_ARCH=64 + $env:CONDA_BLD = "$env:CONDA_BLD" + "-x64" +} + +if ($env:APPVEYOR_PULL_REQUEST_NUMBER -or $env:APPVEYOR_REPO_TAG_NAME -or $env:FORCE_CONDA_BUILD -eq "True") { + # Update PATH, and keep a copy to restore at end of this PowerShell script + $old_path = $env:path + $env:path = "$env:CONDA_BLD;$env:CONDA_BLD\Scripts;" + $env:path + + Write-Host "Starting conda install" -ForegroundColor "Green" + conda config --set always_yes True + conda config --set changeps1 False + conda config --set auto_update_conda False + conda install conda-build jinja2 anaconda-client --quiet + conda info + + # why `2>&1 | %{ "$_" }`? Redirect STDERR to STDOUT + # see: http://stackoverflow.com/a/20950421/5208670 + Write-Host "Starting conda build recipe" -ForegroundColor "Green" + conda build conda.recipe --quiet 2>&1 | %{ "$_" } + + $CONDA_PKG=(conda build conda.recipe --output) + Copy-Item $CONDA_PKG .\dist\ + Write-Host "Completed conda build recipe" -ForegroundColor "Green" + + # Restore PATH back to original + $env:path = $old_path +} else { + Write-Host "Skipping conda build recipe" -ForegroundColor "Green" +} diff --git a/ci/appveyor_run_tests.ps1 b/ci/appveyor_run_tests.ps1 new file mode 100644 index 000000000..b45440fbe --- /dev/null +++ b/ci/appveyor_run_tests.ps1 @@ -0,0 +1,68 @@ +# Script to simplify AppVeyor configuration and resolve path to tools + +# Test Runner framework being used for embedded tests +$CS_RUNNER = "nunit3-console" + +# Needed for ARCH specific runners(NUnit2/XUnit3). Skip for NUnit3 +if ($FALSE -and $env:PLATFORM -eq "x86"){ + $CS_RUNNER = $CS_RUNNER + "-x86" +} + +# Executable paths for OpenCover +# Note if OpenCover fails, it won't affect the exit codes. +$OPENCOVER = Resolve-Path .\packages\OpenCover.*\tools\OpenCover.Console.exe +if ($env:BUILD_OPTS -eq "--xplat"){ + $CS_RUNNER = Resolve-Path $env:USERPROFILE\.nuget\packages\nunit.consolerunner\*\tools\"$CS_RUNNER".exe +} +else{ + $CS_RUNNER = Resolve-Path .\packages\NUnit.*\tools\"$CS_RUNNER".exe +} +$PY = Get-Command python + +# Can't use ".\build\*\Python.EmbeddingTest.dll". Missing framework files. +$CS_TESTS = ".\src\embed_tests\bin\Python.EmbeddingTest.dll" +$RUNTIME_DIR = ".\src\runtime\bin\" + +# Run python tests with C# coverage +Write-Host ("Starting Python tests") -ForegroundColor "Green" +.$OPENCOVER -register:user -searchdirs:"$RUNTIME_DIR" -output:py.coverage ` + -target:"$PY" -targetargs:"-m pytest" ` + -returntargetcode +$PYTHON_STATUS = $LastExitCode +if ($PYTHON_STATUS -ne 0) { + Write-Host "Python tests failed, continuing to embedded tests" -ForegroundColor "Red" +} + +# Run Embedded tests with C# coverage +Write-Host ("Starting embedded tests") -ForegroundColor "Green" +.$OPENCOVER -register:user -searchdirs:"$RUNTIME_DIR" -output:cs.coverage ` + -target:"$CS_RUNNER" -targetargs:"$CS_TESTS" ` + -filter:"+[*]Python.Runtime*" ` + -returntargetcode +$CS_STATUS = $LastExitCode +if ($CS_STATUS -ne 0) { + Write-Host "Embedded tests failed" -ForegroundColor "Red" +} + +if ($env:BUILD_OPTS -eq "--xplat"){ + if ($env:PLATFORM -eq "x64") { + $DOTNET_CMD = "dotnet" + } + else{ + $DOTNET_CMD = "c:\Program Files (x86)\dotnet\dotnet" + } + + # Run Embedded tests for netcoreapp2.0 (OpenCover currently does not supports dotnet core) + Write-Host ("Starting embedded tests for netcoreapp2.0") -ForegroundColor "Green" + &$DOTNET_CMD .\src\embed_tests\bin\netcoreapp2.0_publish\Python.EmbeddingTest.dll + $CS_STATUS = $LastExitCode + if ($CS_STATUS -ne 0) { + Write-Host "Embedded tests for netcoreapp2.0 failed" -ForegroundColor "Red" + } +} + +# Set exit code to fail if either Python or Embedded tests failed +if ($PYTHON_STATUS -ne 0 -or $CS_STATUS -ne 0) { + Write-Host "Tests failed" -ForegroundColor "Red" + $host.SetShouldExit(1) +} diff --git a/ci/install_miniconda.ps1 b/ci/install_miniconda.ps1 deleted file mode 100644 index 5c87ca894..000000000 --- a/ci/install_miniconda.ps1 +++ /dev/null @@ -1,95 +0,0 @@ -# Sample script to install Miniconda under Windows -# Authors: Olivier Grisel, Jonathan Helmus and Kyle Kastner, Robert McGibbon -# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ - -$MINICONDA_URL = "http://repo.continuum.io/miniconda/" - - -function DownloadMiniconda($python_version, $platform_suffix) { - $webclient = New-Object System.Net.WebClient - $filename = "Miniconda3-latest-Windows-" + $platform_suffix + ".exe" - $url = $MINICONDA_URL + $filename - - $basedir = $pwd.Path + "\" - $filepath = $basedir + $filename - if (Test-Path $filename) { - Write-Host "Reusing" $filepath - return $filepath - } - - # Download and retry up to 3 times in case of network transient errors. - Write-Host "Downloading" $filename "from" $url - $retry_attempts = 2 - for ($i=0; $i -lt $retry_attempts; $i++) { - try { - $webclient.DownloadFile($url, $filepath) - break - } - catch [Exception] { - Start-Sleep 1 - } - } - - if (Test-Path $filepath) { - Write-Host "File saved at" $filepath - } else { - # Retry once to get the error message if any at the last try - $webclient.DownloadFile($url, $filepath) - } - return $filepath -} - - -function InstallMiniconda($python_version, $architecture, $python_home) { - Write-Host "Installing Python $python_version $architecture bit to $python_home" - if (Test-Path $python_home) { - Write-Host "$python_home already exists, skipping." - } - if ($architecture -match "32") { - $platform_suffix = "x86" - } else { - $platform_suffix = "x86_64" - } - - $filepath = DownloadMiniconda $python_version $platform_suffix - Write-Host "Installing $filepath to $python_home" - $install_log = $python_home + ".log" - $args = "/S /D=$python_home" - Write-Host $filepath $args - Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru - if (Test-Path $python_home) { - Write-Host "Python $python_version $architecture bit installation complete" - } else { - Write-Host "Failed to install Python in $python_home" - Get-Content -Path $install_log - Exit 1 - } -} - - -function InstallCondaPackages($python_home, $spec) { - $conda_path = $python_home + "\Scripts\conda.exe" - $args = "install --yes " + $spec - Write-Host ("conda " + $args) -ForegroundColor "Green" - Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru -} - - -function UpdateConda($python_home) { - $conda_path = $python_home + "\Scripts\conda.exe" - Write-Host "Updating conda..." -ForegroundColor "Green" - $args = "update --yes conda" - Write-Host $conda_path $args - Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru -} - - -function main() { - Write-Host "Starting install_miniconda.ps1" -ForegroundColor "Green" - InstallMiniconda $env:CONDA_BLD_VERSION $env:CONDA_BLD_ARCH $env:CONDA_BLD - UpdateConda $env:CONDA_BLD - InstallCondaPackages $env:CONDA_BLD "conda-build jinja2 anaconda-client" - Write-Host "Completed install_miniconda.ps1" -ForegroundColor "Green" -} - -main diff --git a/ci/run_with_env.cmd b/ci/run_with_env.cmd deleted file mode 100644 index c88489f2c..000000000 --- a/ci/run_with_env.cmd +++ /dev/null @@ -1,85 +0,0 @@ -:: EXPECTED ENV VARS: PYTHON_ARCH (either x86 or x64) -:: CONDA_PY (either 27, 33, 35 etc. - only major version is extracted) -:: -:: -:: To build extensions for 64 bit Python 3, we need to configure environment -:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of: -:: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1) -:: -:: To build extensions for 64 bit Python 2, we need to configure environment -:: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of: -:: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0) -:: -:: 32 bit builds, and 64-bit builds for 3.5 and beyond, do not require specific -:: environment configurations. -:: -:: Note: this script needs to be run with the /E:ON and /V:ON flags for the -:: cmd interpreter, at least for (SDK v7.0) -:: -:: More details at: -:: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows -:: http://stackoverflow.com/a/13751649/163740 -:: -:: Author: Phil Elson -:: Original Author: Olivier Grisel (https://github.com/ogrisel/python-appveyor-demo) -:: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ -:: -:: Notes about batch files for Python people: -:: -:: Quotes in values are literally part of the values: -:: SET FOO="bar" -:: FOO is now five characters long: " b a r " -:: If you don't want quotes, don't include them on the right-hand side. -:: -:: The CALL lines at the end of this file look redundant, but if you move them -:: outside of the IF clauses, they do not run properly in the SET_SDK_64==Y -:: case, I don't know why. -:: originally from https://github.com/pelson/Obvious-CI/blob/master/scripts/obvci_appveyor_python_build_env.cmd -:: https://github.com/alimanfoo/zarr/blob/master/build.cmd -:: https://github.com/cython/cython/blob/master/appveyor/run_with_env.cmd -:: https://github.com/cjrh/easycython/blob/master/appveyor/setup_build_env.cmd -@ECHO OFF - -SET COMMAND_TO_RUN=%* -SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows - -:: CONDA_PY style, such as 27, 34 etc. -SET MAJOR_PYTHON_VERSION=%CONDA_PY:~0,1% -SET MINOR_PYTHON_VERSION=%CONDA_PY:~1,1% - -:: Based on the Python version, determine what SDK version to use, and whether -:: to set the SDK for 64-bit. -IF %MAJOR_PYTHON_VERSION% == 2 ( - SET WINDOWS_SDK_VERSION="v7.0" - SET SET_SDK_64=Y -) ELSE IF %MAJOR_PYTHON_VERSION% == 3 ( - SET WINDOWS_SDK_VERSION="v7.1" - IF %MINOR_PYTHON_VERSION% LEQ 4 ( - SET SET_SDK_64=Y - ) ELSE ( - SET SET_SDK_64=N - ) -) ELSE ( - ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%" - EXIT /B 1 -) - -IF "%PYTHON_ARCH%"=="64" ( - IF %SET_SDK_64% == Y ( - ECHO Configuring Windows SDK %WINDOWS_SDK_VERSION% for Python %MAJOR_PYTHON_VERSION% on a 64 bit architecture - SET DISTUTILS_USE_SDK=1 - SET MSSdk=1 - "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION% - "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release - ECHO Executing: %COMMAND_TO_RUN% - call %COMMAND_TO_RUN% || EXIT /B 1 - ) ELSE ( - ECHO Using default MSVC build environment for 64 bit architecture - ECHO Executing: %COMMAND_TO_RUN% - call %COMMAND_TO_RUN% || EXIT /B 1 - ) -) ELSE ( - ECHO Using default MSVC build environment for 32 bit architecture - ECHO Executing: %COMMAND_TO_RUN% - call %COMMAND_TO_RUN% || EXIT /B 1 -) diff --git a/conda.recipe/README.md b/conda.recipe/README.md new file mode 100644 index 000000000..42241999f --- /dev/null +++ b/conda.recipe/README.md @@ -0,0 +1,5 @@ +# Conda Recipe + +The files here are needed to build Python.Net with conda + +http://conda.pydata.org/docs/building/recipe.html diff --git a/conda.recipe/bld.bat b/conda.recipe/bld.bat index d846fc738..27b55f2de 100644 --- a/conda.recipe/bld.bat +++ b/conda.recipe/bld.bat @@ -1,13 +1,6 @@ :: build it :: set path to modern MSBuild -set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH% +set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;C:\Program Files (x86)\MSBuild\15.0\Bin;%PATH% %PYTHON% setup.py install - -:: copy our compiled library -set SRC=%RECIPE_DIR%\.. -set DEST=%SP_DIR% - -:: Install step -copy %SRC%\Python.Runtime.dll.config %DEST% diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml index da62edc90..3641185bb 100644 --- a/conda.recipe/meta.yaml +++ b/conda.recipe/meta.yaml @@ -1,6 +1,6 @@ package: name: pythonnet - version: {{ environ.get('GIT_DESCRIBE_TAG', '').replace('-dev', '.dev') }} + version: "2.4.0.dev0" build: skip: True # [not win] @@ -26,3 +26,4 @@ test: about: home: https://github.com/pythonnet/pythonnet license: MIT + license_file: LICENSE diff --git a/demo/DynamicGrid.py b/demo/DynamicGrid.py new file mode 100644 index 000000000..951a6c248 --- /dev/null +++ b/demo/DynamicGrid.py @@ -0,0 +1,23 @@ +import clr +import sys +if sys.platform.lower() not in ['cli','win32']: + print("only windows is supported for wpf") +clr.AddReference(r"wpf\PresentationFramework") +from System.IO import StreamReader +from System.Windows.Markup import XamlReader +from System.Threading import Thread, ThreadStart, ApartmentState +from System.Windows import Application, Window + + +class MyWindow(Window): + def __init__(self): + stream = StreamReader("DynamicGrid.xaml") + window = XamlReader.Load(stream.BaseStream) + Application().Run(window) + + +if __name__ == '__main__': + thread = Thread(ThreadStart(MyWindow)) + thread.SetApartmentState(ApartmentState.STA) + thread.Start() + thread.Join() diff --git a/demo/DynamicGrid.xaml b/demo/DynamicGrid.xaml new file mode 100644 index 000000000..3c82eb16d --- /dev/null +++ b/demo/DynamicGrid.xaml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/pythonnet.15.sln b/pythonnet.15.sln new file mode 100644 index 000000000..f2015e480 --- /dev/null +++ b/pythonnet.15.sln @@ -0,0 +1,194 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26730.3 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Python.Runtime.15", "src/runtime/Python.Runtime.15.csproj", "{2759F4FF-716B-4828-916F-50FA86613DFC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Python.EmbeddingTest.15", "src/embed_tests/Python.EmbeddingTest.15.csproj", "{66B8D01A-9906-452A-B09E-BF75EA76468F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "clrmodule.15", "src/clrmodule/clrmodule.15.csproj", "{E08678D4-9A52-4AD5-B63D-8EBC7399981B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Console.15", "src/console/Console.15.csproj", "{CDAD305F-8E72-492C-A314-64CF58D472A0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Python.Test.15", "src/testing/Python.Test.15.csproj", "{F94B547A-E97E-4500-8D53-B4D64D076E5F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + DebugMono|x64 = DebugMono|x64 + DebugMono|x86 = DebugMono|x86 + DebugMonoPY3|x64 = DebugMonoPY3|x64 + DebugMonoPY3|x86 = DebugMonoPY3|x86 + DebugWin|x64 = DebugWin|x64 + DebugWin|x86 = DebugWin|x86 + DebugWinPY3|x64 = DebugWinPY3|x64 + DebugWinPY3|x86 = DebugWinPY3|x86 + ReleaseMono|x64 = ReleaseMono|x64 + ReleaseMono|x86 = ReleaseMono|x86 + ReleaseMonoPY3|x64 = ReleaseMonoPY3|x64 + ReleaseMonoPY3|x86 = ReleaseMonoPY3|x86 + ReleaseWin|x64 = ReleaseWin|x64 + ReleaseWin|x86 = ReleaseWin|x86 + ReleaseWinPY3|x64 = ReleaseWinPY3|x64 + ReleaseWinPY3|x86 = ReleaseWinPY3|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMono|x64.ActiveCfg = DebugMono|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMono|x64.Build.0 = DebugMono|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMono|x86.ActiveCfg = DebugMono|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMono|x86.Build.0 = DebugMono|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWin|x64.ActiveCfg = DebugWin|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWin|x64.Build.0 = DebugWin|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWin|x86.ActiveCfg = DebugWin|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWin|x86.Build.0 = DebugWin|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWinPY3|x64.Build.0 = DebugWinPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWinPY3|x86.Build.0 = DebugWinPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMono|x64.ActiveCfg = ReleaseMono|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMono|x64.Build.0 = ReleaseMono|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMono|x86.ActiveCfg = ReleaseMono|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMono|x86.Build.0 = ReleaseMono|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWin|x64.ActiveCfg = ReleaseWin|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWin|x64.Build.0 = ReleaseWin|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWin|x86.Build.0 = ReleaseWin|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|Any CPU + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMono|x64.ActiveCfg = DebugMono|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMono|x64.Build.0 = DebugMono|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMono|x86.ActiveCfg = DebugMono|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMono|x86.Build.0 = DebugMono|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWin|x64.ActiveCfg = DebugWin|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWin|x64.Build.0 = DebugWin|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWin|x86.ActiveCfg = DebugWin|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWin|x86.Build.0 = DebugWin|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugMono|x64.ActiveCfg = DebugMono|x64 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugMono|x86.ActiveCfg = DebugMono|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWin|x64.ActiveCfg = DebugWin|x64 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWin|x64.Build.0 = DebugWin|x64 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWin|x86.ActiveCfg = DebugWin|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWin|x86.Build.0 = DebugWin|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMono|x64.ActiveCfg = DebugMono|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMono|x64.Build.0 = DebugMono|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMono|x86.ActiveCfg = DebugMono|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMono|x86.Build.0 = DebugMono|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWin|x64.ActiveCfg = DebugWin|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWin|x64.Build.0 = DebugWin|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWin|x86.ActiveCfg = DebugWin|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWin|x86.Build.0 = DebugWin|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMono|x64.ActiveCfg = DebugMono|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMono|x64.Build.0 = DebugMono|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMono|x86.ActiveCfg = DebugMono|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMono|x86.Build.0 = DebugMono|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWin|x64.ActiveCfg = DebugWin|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWin|x64.Build.0 = DebugWin|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWin|x86.ActiveCfg = DebugWin|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWin|x86.Build.0 = DebugWin|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A6347B90-BBE6-4E45-90BF-1BD8B76069E3} + EndGlobalSection +EndGlobal diff --git a/pythonnet.sln b/pythonnet.sln index 0a4dbe1f7..c5afd66c3 100644 --- a/pythonnet.sln +++ b/pythonnet.sln @@ -1,7 +1,6 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.30110.0 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Python.Runtime", "src\runtime\Python.Runtime.csproj", "{097B4AC0-74E9-4C58-BCF8-C69746EC8271}" EndProject @@ -17,90 +16,174 @@ Global GlobalSection(SolutionConfigurationPlatforms) = preSolution DebugMono|x64 = DebugMono|x64 DebugMono|x86 = DebugMono|x86 + DebugMonoPY3|x64 = DebugMonoPY3|x64 + DebugMonoPY3|x86 = DebugMonoPY3|x86 DebugWin|x64 = DebugWin|x64 DebugWin|x86 = DebugWin|x86 + DebugWinPY3|x64 = DebugWinPY3|x64 + DebugWinPY3|x86 = DebugWinPY3|x86 ReleaseMono|x64 = ReleaseMono|x64 ReleaseMono|x86 = ReleaseMono|x86 + ReleaseMonoPY3|x64 = ReleaseMonoPY3|x64 + ReleaseMonoPY3|x86 = ReleaseMonoPY3|x86 ReleaseWin|x64 = ReleaseWin|x64 ReleaseWin|x86 = ReleaseWin|x86 + ReleaseWinPY3|x64 = ReleaseWinPY3|x64 + ReleaseWinPY3|x86 = ReleaseWinPY3|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x64.ActiveCfg = DebugMono|x64 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x64.Build.0 = DebugMono|x64 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x86.ActiveCfg = DebugMono|x86 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x86.Build.0 = DebugMono|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x64.ActiveCfg = DebugWin|x64 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x64.Build.0 = DebugWin|x64 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x86.ActiveCfg = DebugWin|x86 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x86.Build.0 = DebugWin|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x64.ActiveCfg = DebugMono|x64 {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x64.Build.0 = DebugMono|x64 {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x86.ActiveCfg = DebugMono|x86 {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x86.Build.0 = DebugMono|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWin|x64.ActiveCfg = DebugWin|x64 {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWin|x64.Build.0 = DebugWin|x64 {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWin|x86.ActiveCfg = DebugWin|x86 {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWin|x86.Build.0 = DebugWin|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMono|x64.ActiveCfg = DebugMono|x64 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMono|x64.Build.0 = DebugMono|x64 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMono|x86.ActiveCfg = DebugMono|x86 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMono|x86.Build.0 = DebugMono|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWin|x64.ActiveCfg = DebugWin|x64 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWin|x64.Build.0 = DebugWin|x64 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWin|x86.ActiveCfg = DebugWin|x86 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWin|x86.Build.0 = DebugWin|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x64.ActiveCfg = DebugMono_x86|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x64.Build.0 = DebugMono_x86|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x86.ActiveCfg = DebugMono_x86|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x86.Build.0 = DebugMono_x86|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x64.ActiveCfg = DebugMono_x86|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x64.Build.0 = DebugMono_x86|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x86.ActiveCfg = DebugMono_x86|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x86.Build.0 = DebugMono_x86|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x64.ActiveCfg = Release|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x64.Build.0 = Release|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x86.ActiveCfg = Release|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x86.Build.0 = Release|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x64.ActiveCfg = Release|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x64.Build.0 = Release|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x86.ActiveCfg = Release|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x86.Build.0 = Release|x86 - {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugMono|x64.ActiveCfg = DebugWin|x64 - {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugMono|x86.ActiveCfg = DebugWin|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x64.ActiveCfg = DebugMono|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x64.Build.0 = DebugMono|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x86.ActiveCfg = DebugMono|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x86.Build.0 = DebugMono|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x64.ActiveCfg = DebugWin|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x64.Build.0 = DebugWin|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x86.ActiveCfg = DebugWin|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x86.Build.0 = DebugWin|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 + {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugMono|x64.ActiveCfg = DebugMono|x64 + {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugMono|x86.ActiveCfg = DebugMono|x86 + {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 + {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWin|x64.ActiveCfg = DebugWin|x64 {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWin|x64.Build.0 = DebugWin|x64 {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWin|x86.ActiveCfg = DebugWin|x86 {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWin|x86.Build.0 = DebugWin|x86 - {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseMono|x64.ActiveCfg = ReleaseWin|x64 - {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseMono|x86.ActiveCfg = ReleaseWin|x86 + {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 + {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 + {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 + {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 + {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 + {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 + {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 + {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 + {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 + {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 + {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 + {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..24679b2af --- /dev/null +++ b/requirements.txt @@ -0,0 +1,11 @@ +# Requirements for both Travis and AppVeyor +pytest==3.2.5 +coverage + +# Coverage upload +codecov + +# Platform specific requirements +pip; sys_platform == 'win32' +wheel; sys_platform == 'win32' +pycparser; sys_platform != 'win32' diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 000000000..38aa3eb3d --- /dev/null +++ b/setup.cfg @@ -0,0 +1,10 @@ +# [bumpversion] comments. bumpversion deleted all comments on its file. +# Don't combine `.bumpversion.cfg` with `setup.cfg`. Messes up formatting. +# Don't use `first_value = 1`. It will break `release` bump +# Keep `optional = dummy` needed to bump to release. +# See: https://github.com/peritus/bumpversion/issues/59 + +[tool:pytest] +xfail_strict = True +# -r fsxX: show extra summary info for: (f)ailed, (s)kip, (x)failed, (X)passed +addopts = -r fsxX --color=yes --durations=5 diff --git a/setup.py b/setup.py index f8409799a..4ec2a2113 100644 --- a/setup.py +++ b/setup.py @@ -6,124 +6,163 @@ an egg or wheel. """ -from setuptools import setup, Extension -from distutils.command.build_ext import build_ext -from distutils.command.install_lib import install_lib -from distutils.command.install_data import install_data -from distutils.sysconfig import get_config_var -from distutils.spawn import find_executable -from distutils import log -from platform import architecture -from subprocess import Popen, CalledProcessError, PIPE, check_call -from glob import glob +import collections import fnmatch -import sys +import glob import os +import subprocess +import sys +import sysconfig +from distutils import spawn +from distutils.command import install, build, build_ext, install_data, install_lib +from wheel import bdist_wheel + +from setuptools import Extension, setup +# Allow config/verbosity to be set from cli +# http://stackoverflow.com/a/4792601/5208670 CONFIG = "Release" # Release or Debug -DEVTOOLS = "MsDev" if sys.platform == "win32" else "Mono" VERBOSITY = "minimal" # quiet, minimal, normal, detailed, diagnostic -PLATFORM = "x64" if architecture()[0] == "64bit" else "x86" +is_64bits = sys.maxsize > 2**32 +DEVTOOLS = "MsDev" if sys.platform == "win32" else "Mono" +ARCH = "x64" if is_64bits else "x86" +PY_MAJOR = sys.version_info[0] +PY_MINOR = sys.version_info[1] -def _find_msbuild_tool(tool="msbuild.exe", use_windows_sdk=False): - """Return full path to one of the Microsoft build tools""" - path = find_executable(tool) - if path: - return path +############################################################################### +# Windows Keys Constants for MSBUILD tools +RegKey = collections.namedtuple('RegKey', 'sdk_name key value_name suffix') +vs_python = "Programs\\Common\\Microsoft\\Visual C++ for Python\\9.0\\WinSDK" +vs_root = "SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\{0}" +sdks_root = "SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v{0}Win32Tools" +kits_root = "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots" +kits_suffix = os.path.join("bin", ARCH) - try: - import _winreg - except ImportError: - import winreg as _winreg - - keys_to_check = [] - if use_windows_sdk: - sdks_root = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows" - kits_root = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots" - kits_suffix = os.path.join("bin", PLATFORM) - keys_to_check.extend([ - ("Windows Kit 10.0", kits_root, "KitsRoot10", kits_suffix), - ("Windows Kit 8.1", kits_root, "KitsRoot81", kits_suffix), - ("Windows Kit 8.0", kits_root, "KitsRoot", kits_suffix), - ("Windows SDK 7.1A", sdks_root + r"\v7.1A\WinSDK-Win32Tools", "InstallationFolder"), - ("Windows SDK 7.1", sdks_root + r"\v7.1\WinSDKWin32Tools", "InstallationFolder"), - ("Windows SDK 7.0A", sdks_root + r"\v7.0A\WinSDK-Win32Tools", "InstallationFolder"), - ("Windows SDK 7.0", sdks_root + r"\v7.0\WinSDKWin32Tools", "InstallationFolder"), - ("Windows SDK 6.0A", sdks_root + r"\v6.0A\WinSDKWin32Tools", "InstallationFolder") - ]) - else: - vs_root = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions" - keys_to_check.extend([ - ("MSBuild 14", vs_root + r"\14.0", "MSBuildToolsPath"), - ("MSBuild 12", vs_root + r"\12.0", "MSBuildToolsPath"), - ("MSBuild 4", vs_root + r"\4.0", "MSBuildToolsPath"), - ("MSBuild 3.5", vs_root + r"\3.5", "MSBuildToolsPath"), - ("MSBuild 2.0", vs_root + r"\2.0", "MSBuildToolsPath") - ]) - - # read the possible tools paths from the various registry locations - paths_to_check = [] - hreg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - try: - for key_to_check in keys_to_check: - sdk_name, key, value_name = key_to_check[:3] - suffix = key_to_check[3] if len(key_to_check) > 3 else None - hkey = None - try: - hkey = _winreg.OpenKey(hreg, key) - val, type_ = _winreg.QueryValueEx(hkey, value_name) - if type_ != _winreg.REG_SZ: - continue - if suffix: - val = os.path.join(val, suffix) - paths_to_check.append((sdk_name, val)) - except WindowsError: - pass - finally: - if hkey: - hkey.Close() - finally: - hreg.Close() - - # Add Visual C++ for Python as a fall-back in case one - # of the other Windows SDKs isn't installed - if use_windows_sdk: - localappdata = os.environ["LOCALAPPDATA"] - pywinsdk = localappdata + r"\Programs\Common\Microsoft\Visual C++ for Python\9.0\WinSDK\Bin" - if PLATFORM == "x64": - pywinsdk += r"\x64" - paths_to_check.append(("Visual C++ for Python", pywinsdk)) - - for sdk_name, path in paths_to_check: - path = os.path.join(path, tool) - if os.path.exists(path): - log.info("Using %s from %s" % (tool, sdk_name)) - return path +WIN_SDK_KEYS = ( + RegKey(sdk_name="Windows Kit 10.0", key=kits_root, + value_name="KitsRoot10", suffix=os.path.join("bin", "10.0.16299.0", ARCH)), + + RegKey(sdk_name="Windows Kit 10.0", key=kits_root, + value_name="KitsRoot10", suffix=os.path.join("bin", "10.0.15063.0", ARCH)), + + RegKey(sdk_name="Windows Kit 10.0", key=kits_root, + value_name="KitsRoot10", suffix=kits_suffix), + + RegKey(sdk_name="Windows Kit 8.1", key=kits_root, + value_name="KitsRoot81", suffix=kits_suffix), + + RegKey(sdk_name="Windows Kit 8.0", key=kits_root, + value_name="KitsRoot", suffix=kits_suffix), + + RegKey(sdk_name="Windows SDK 7.1A", key=sdks_root.format("7.1A\\WinSDK-"), + value_name="InstallationFolder", suffix=""), + + RegKey(sdk_name="Windows SDK 7.1", key=sdks_root.format("7.1\\WinSDK"), + value_name="InstallationFolder", suffix=""), + + RegKey(sdk_name="Windows SDK 7.0A", key=sdks_root.format("7.0A\\WinSDK-"), + value_name="InstallationFolder", suffix=""), + + RegKey(sdk_name="Windows SDK 7.0", key=sdks_root.format("7.0\\WinSDK"), + value_name="InstallationFolder", suffix=""), + + RegKey(sdk_name="Windows SDK 6.0A", key=sdks_root.format("6.0A\\WinSDK"), + value_name="InstallationFolder", suffix=""), +) - raise RuntimeError("%s could not be found" % tool) +VS_KEYS = ( + RegKey(sdk_name="MSBuild 15", key=vs_root.format("15.0"), + value_name="MSBuildToolsPath", suffix=""), + RegKey(sdk_name="MSBuild 14", key=vs_root.format("14.0"), + value_name="MSBuildToolsPath", suffix=""), -if DEVTOOLS == "MsDev": - _xbuild = "\"%s\"" % _find_msbuild_tool("msbuild.exe") - _defines_sep = ";" - _config = "%sWin" % CONFIG + RegKey(sdk_name="MSBuild 12", key=vs_root.format("12.0"), + value_name="MSBuildToolsPath", suffix=""), + + RegKey(sdk_name="MSBuild 4", key=vs_root.format("4.0"), + value_name="MSBuildToolsPath", suffix=""), + + RegKey(sdk_name="MSBuild 3.5", key=vs_root.format("3.5"), + value_name="MSBuildToolsPath", suffix=""), + + RegKey(sdk_name="MSBuild 2.0", key=vs_root.format("2.0"), + value_name="MSBuildToolsPath", suffix=""), +) + + +############################################################################### +def _check_output(*args, **kwargs): + """Check output wrapper for py2/py3 compatibility""" + output = subprocess.check_output(*args, **kwargs) + if PY_MAJOR == 2: + return output + return output.decode("ascii") + + +def _get_interop_filename(): + """interopXX.cs is auto-generated as part of the build. + For common windows platforms pre-generated files are included + as most windows users won't have Clang installed, which is + required to generate the file. + """ + interop_filename = "interop{0}{1}{2}.cs".format( + PY_MAJOR, PY_MINOR, getattr(sys, "abiflags", "")) + return os.path.join("src", "runtime", interop_filename) + + +def _get_source_files(): + """Walk project and collect the files needed for ext_module""" + for ext in (".sln", ): + for path in glob.glob("*" + ext): + yield path + + for root, dirnames, filenames in os.walk("src"): + for ext in (".cs", ".csproj", ".snk", ".config", + ".py", ".c", ".h", ".ico"): + for filename in fnmatch.filter(filenames, "*" + ext): + yield os.path.join(root, filename) + + for root, dirnames, filenames in os.walk("tools"): + for ext in (".exe", ".py", ".c", ".h"): + for filename in fnmatch.filter(filenames, "*" + ext): + yield os.path.join(root, filename) -elif DEVTOOLS == "Mono": - _xbuild = "xbuild" - _defines_sep = "," - _config = "%sMono" % CONFIG -else: - raise NotImplementedError( - "DevTools %s not supported (use MsDev or Mono)" % DEVTOOLS) +def _get_long_description(): + """Helper to populate long_description for pypi releases""" + try: + import pypandoc + return pypandoc.convert('README.md', 'rst') + except ImportError: + return '.Net and Mono integration for Python' + +def _update_xlat_devtools(): + global DEVTOOLS + if DEVTOOLS == "MsDev": + DEVTOOLS = "MsDev15" + elif DEVTOOLS == "Mono": + DEVTOOLS = "dotnet" + +class BuildExtPythonnet(build_ext.build_ext): + user_options = build_ext.build_ext.user_options + [ + ('xplat', None, None) + ] + def initialize_options(self): + build_ext.build_ext.initialize_options(self) + self.xplat = None + def finalize_options(self): + build_ext.build_ext.finalize_options(self) -class PythonNET_BuildExt(build_ext): def build_extension(self, ext): + if self.xplat: + _update_xlat_devtools() + """Builds the .pyd file using msbuild or xbuild""" if ext.name != "clr": - return build_ext.build_extension(self, ext) + return build_ext.build_ext.build_extension(self, ext) # install packages using nuget self._install_packages() @@ -135,6 +174,7 @@ def build_extension(self, ext): # Up to Python 3.2 sys.maxunicode is used to determine the size of # Py_UNICODE, but from 3.3 onwards Py_UNICODE is a typedef of wchar_t. + # TODO: Is this doing the right check for Py27? if sys.version_info[:2] <= (3, 2): unicode_width = 2 if sys.maxunicode < 0x10FFFF else 4 else: @@ -142,25 +182,24 @@ def build_extension(self, ext): unicode_width = ctypes.sizeof(ctypes.c_wchar) defines = [ - "PYTHON%d%d" % (sys.version_info[:2]), - "PYTHON%d" % (sys.version_info[:1]), # Python Major Version - "UCS%d" % unicode_width, + "PYTHON{0}{1}".format(PY_MAJOR, PY_MINOR), + "PYTHON{0}".format(PY_MAJOR), # Python Major Version + "UCS{0}".format(unicode_width), ] if CONFIG == "Debug": defines.extend(["DEBUG", "TRACE"]) - if sys.platform != "win32" and DEVTOOLS == "Mono": - if sys.platform == "darwin": - defines.append("MONO_OSX") - else: - defines.append("MONO_LINUX") + if sys.platform != "win32" and (DEVTOOLS == "Mono" or DEVTOOLS == "dotnet"): + on_darwin = sys.platform == "darwin" + defines.append("MONO_OSX" if on_darwin else "MONO_LINUX") # Check if --enable-shared was set when Python was built - enable_shared = get_config_var("Py_ENABLE_SHARED") + enable_shared = sysconfig.get_config_var("Py_ENABLE_SHARED") if enable_shared: # Double-check if libpython is linked dynamically with python - lddout = _check_output(["ldd", sys.executable]) + ldd_cmd = ["otool", "-L"] if on_darwin else ["ldd"] + lddout = _check_output(ldd_cmd + [sys.executable]) if 'libpython' not in lddout: enable_shared = False @@ -172,50 +211,82 @@ def build_extension(self, ext): defines.append("PYTHON_WITH_PYDEBUG") if "m" in sys.abiflags: defines.append("PYTHON_WITH_PYMALLOC") - if "u" in sys.abiflags: - defines.append("PYTHON_WITH_WIDE_UNICODE") # check the interop file exists, and create it if it doesn't interop_file = _get_interop_filename() if not os.path.exists(interop_file): + self.debug_print("Creating {0}".format(interop_file)) geninterop = os.path.join("tools", "geninterop", "geninterop.py") - _check_output([sys.executable, geninterop, interop_file]) + subprocess.check_call([sys.executable, geninterop, interop_file]) + + if DEVTOOLS == "MsDev": + _xbuild = '"{0}"'.format(self._find_msbuild_tool("msbuild.exe")) + _config = "{0}Win".format(CONFIG) + _solution_file = 'pythonnet.sln' + _custom_define_constants = False + elif DEVTOOLS == "MsDev15": + _xbuild = '"{0}"'.format(self._find_msbuild_tool_15()) + _config = "{0}Win".format(CONFIG) + _solution_file = 'pythonnet.15.sln' + _custom_define_constants = True + elif DEVTOOLS == "Mono": + _xbuild = 'xbuild' + _config = "{0}Mono".format(CONFIG) + _solution_file = 'pythonnet.sln' + _custom_define_constants = False + elif DEVTOOLS == "dotnet": + _xbuild = 'dotnet msbuild' + _config = "{0}Mono".format(CONFIG) + _solution_file = 'pythonnet.15.sln' + _custom_define_constants = True + else: + raise NotImplementedError( + "DevTool {0} not supported (use MsDev/MsDev15/Mono/dotnet)".format(DEVTOOLS)) cmd = [ _xbuild, - "pythonnet.sln", - "/p:Configuration=%s" % _config, - "/p:Platform=%s" % PLATFORM, - "/p:DefineConstants=\"%s\"" % _defines_sep.join(defines), - "/p:PythonBuildDir=\"%s\"" % os.path.abspath(dest_dir), - "/p:PythonInteropFile=\"%s\"" % os.path.basename(interop_file), - "/verbosity:%s" % VERBOSITY, + _solution_file, + '/p:Configuration={}'.format(_config), + '/p:Platform={}'.format(ARCH), + '/p:{}DefineConstants="{}"'.format('Custom' if _custom_define_constants else '','%3B'.join(defines)), + '/p:PythonBuildDir="{}"'.format(os.path.abspath(dest_dir)), + '/p:PythonInteropFile="{}"'.format(os.path.basename(interop_file)), + '/verbosity:{}'.format(VERBOSITY), ] manifest = self._get_manifest(dest_dir) if manifest: - cmd.append("/p:PythonManifest=\"%s\"" % manifest) + cmd.append('/p:PythonManifest="{0}"'.format(manifest)) - self.announce("Building: %s" % " ".join(cmd)) - use_shell = True if DEVTOOLS == "Mono" else False - check_call(" ".join(cmd + ["/t:Clean"]), shell=use_shell) - check_call(" ".join(cmd + ["/t:Build"]), shell=use_shell) + self.debug_print("Building: {0}".format(" ".join(cmd))) + use_shell = True if DEVTOOLS == "Mono" or DEVTOOLS == "dotnet" else False - if DEVTOOLS == "Mono": - self._build_monoclr(ext) + subprocess.check_call(" ".join(cmd + ["/t:Clean"]), shell=use_shell) + subprocess.check_call(" ".join(cmd + ["/t:Build"]), shell=use_shell) + if DEVTOOLS == "MsDev15" or DEVTOOLS == "dotnet": + subprocess.check_call(" ".join(cmd + ['"/t:Console_15:publish;Python_EmbeddingTest_15:publish"', "/p:TargetFramework=netcoreapp2.0"]), shell=use_shell) + if DEVTOOLS == "Mono" or DEVTOOLS == "dotnet": + self._build_monoclr() def _get_manifest(self, build_dir): - if DEVTOOLS == "MsDev" and sys.version_info[:2] > (2, 5): - mt = _find_msbuild_tool("mt.exe", use_windows_sdk=True) - manifest = os.path.abspath(os.path.join(build_dir, "app.manifest")) - cmd = [mt, '-inputresource:"%s"' % sys.executable, - '-out:"%s"' % manifest] - self.announce("Extracting manifest from %s" % sys.executable) - check_call(" ".join(cmd), shell=False) - return manifest - - def _build_monoclr(self, ext): - mono_libs = _check_output("pkg-config --libs mono-2", shell=True) + if DEVTOOLS != "MsDev" and DEVTOOLS != "MsDev15": + return + mt = self._find_msbuild_tool("mt.exe", use_windows_sdk=True) + manifest = os.path.abspath(os.path.join(build_dir, "app.manifest")) + cmd = [mt, '-inputresource:"{0}"'.format(sys.executable), + '-out:"{0}"'.format(manifest)] + self.debug_print("Extracting manifest from {}".format(sys.executable)) + subprocess.check_call(" ".join(cmd), shell=False) + return manifest + + def _build_monoclr(self): + try: + mono_libs = _check_output("pkg-config --libs mono-2", shell=True) + except: + if DEVTOOLS == "dotnet": + print("Skipping building monoclr module...") + return + raise mono_cflags = _check_output("pkg-config --cflags mono-2", shell=True) glib_libs = _check_output("pkg-config --libs glib-2.0", shell=True) glib_cflags = _check_output("pkg-config --cflags glib-2.0", shell=True) @@ -223,55 +294,142 @@ def _build_monoclr(self, ext): libs = mono_libs.strip() + " " + glib_libs.strip() # build the clr python module - clr_ext = Extension("clr", - sources=[ - "src/monoclr/pynetinit.c", - "src/monoclr/clrmod.c" - ], - extra_compile_args=cflags.split(" "), - extra_link_args=libs.split(" ")) - - build_ext.build_extension(self, clr_ext) + clr_ext = Extension( + "clr", + sources=[ + "src/monoclr/pynetinit.c", + "src/monoclr/clrmod.c" + ], + extra_compile_args=cflags.split(" "), + extra_link_args=libs.split(" ") + ) + + build_ext.build_ext.build_extension(self, clr_ext) def _install_packages(self): """install packages using nuget""" - nuget = os.path.join("tools", "nuget", "nuget.exe") - use_shell = False - if DEVTOOLS == "Mono": - nuget = "mono %s" % nuget - use_shell = True + use_shell = DEVTOOLS == "Mono" or DEVTOOLS == "dotnet" - cmd = "%s update -self" % nuget - self.announce("Updating NuGet: %s" % cmd) - check_call(cmd, shell=use_shell) + if DEVTOOLS == "MsDev15" or DEVTOOLS == "dotnet": + if DEVTOOLS == "MsDev15": + _config = "{0}Win".format(CONFIG) + elif DEVTOOLS == "dotnet": + _config = "{0}Mono".format(CONFIG) + + cmd = "dotnet msbuild /t:Restore pythonnet.15.sln /p:Configuration={0} /p:Platform={1}".format(_config, ARCH) + self.debug_print("Updating packages with xplat: {0}".format(cmd)) + subprocess.check_call(cmd, shell=use_shell) + else: + nuget = os.path.join("tools", "nuget", "nuget.exe") - cmd = "%s restore pythonnet.sln -o packages" % nuget - self.announce("Installing packages: %s" % cmd) - check_call(cmd, shell=use_shell) + if DEVTOOLS == "Mono": + nuget = "mono {0}".format(nuget) + + cmd = "{0} update -self".format(nuget) + self.debug_print("Updating NuGet: {0}".format(cmd)) + subprocess.check_call(cmd, shell=use_shell) + + cmd = "{0} restore pythonnet.sln -o packages".format(nuget) + self.debug_print("Installing packages: {0}".format(cmd)) + subprocess.check_call(cmd, shell=use_shell) + + def _find_msbuild_tool(self, tool="msbuild.exe", use_windows_sdk=False): + """Return full path to one of the Microsoft build tools""" + + # trying to search path with help of vswhere when MSBuild 15.0 and higher installed. + if tool=="msbuild.exe" and use_windows_sdk==False: + try: + basePathes = subprocess.check_output( + ["tools\\vswhere\\vswhere.exe", "-latest", + "-version", "[15.0, 16.0)", + "-requires", "Microsoft.Component.MSBuild", + "-property", "InstallationPath"]).splitlines() + if len(basePathes): + return os.path.join(basePathes[0].decode(sys.stdout.encoding or "utf-8"), "MSBuild", "15.0", "Bin", "MSBuild.exe") + except: + pass # keep trying to search by old method. + + # Search in PATH first + path = spawn.find_executable(tool) + if path: + return path + + # Search within registry to find build tools + try: # PY2 + import _winreg as winreg + except ImportError: # PY3 + import winreg + + keys_to_check = WIN_SDK_KEYS if use_windows_sdk else VS_KEYS + hklm = winreg.HKEY_LOCAL_MACHINE + for rkey in keys_to_check: + try: + with winreg.OpenKey(hklm, rkey.key) as hkey: + val, type_ = winreg.QueryValueEx(hkey, rkey.value_name) + if type_ != winreg.REG_SZ: + continue + path = os.path.join(val, rkey.suffix, tool) + if os.path.exists(path): + self.debug_print("Using {0} from {1}".format( + tool, rkey.sdk_name)) + return path + except WindowsError: + # Key doesn't exist + pass + # Add Visual C++ for Python as a fall-back in case one + # of the other Windows SDKs isn't installed. + # TODO: Extend checking by using setuptools/msvc.py? + if use_windows_sdk: + sdk_name = "Visual C++ for Python" + localappdata = os.environ["LOCALAPPDATA"] + suffix = "Bin\\x64" if ARCH == "x64" else "Bin" + path = os.path.join(localappdata, vs_python, suffix, tool) + if os.path.exists(path): + self.debug_print("Using {0} from {1}".format(tool, sdk_name)) + return path + + raise RuntimeError("{0} could not be found".format(tool)) + + def _find_msbuild_tool_15(self): + """Return full path to one of the Microsoft build tools""" + try: + basePathes = subprocess.check_output( + ["tools\\vswhere\\vswhere.exe", "-latest", + "-version", "[15.0, 16.0)", + "-requires", "Microsoft.Component.MSBuild", + "-property", "InstallationPath"]).splitlines() + if len(basePathes): + return os.path.join(basePathes[0].decode(sys.stdout.encoding or "utf-8"), "MSBuild", "15.0", "Bin", "MSBuild.exe") + else: + raise RuntimeError("MSBuild >=15.0 could not be found.") + except subprocess.CalledProcessError as e: + raise RuntimeError("MSBuild >=15.0 could not be found. {0}".format(e.output)) -class PythonNET_InstallLib(install_lib): +class InstallLibPythonnet(install_lib.install_lib): def install(self): if not os.path.isdir(self.build_dir): - self.warn("'%s' does not exist -- no Python modules to install" % - self.build_dir) + self.warn("'{0}' does not exist -- no Python modules" + " to install".format(self.build_dir)) return if not os.path.exists(self.install_dir): self.mkpath(self.install_dir) # only copy clr.pyd/.so - for srcfile in glob(os.path.join(self.build_dir, "clr.*")): - destfile = os.path.join(self.install_dir, os.path.basename(srcfile)) + for srcfile in glob.glob(os.path.join(self.build_dir, "clr.*")): + destfile = os.path.join( + self.install_dir, os.path.basename(srcfile)) self.copy_file(srcfile, destfile) -class PythonNET_InstallData(install_data): +class InstallDataPythonnet(install_data.install_data): def run(self): build_cmd = self.get_finalized_command("build_ext") install_cmd = self.get_finalized_command("install") build_lib = os.path.abspath(build_cmd.build_lib) - install_platlib = os.path.relpath(install_cmd.install_platlib, self.install_dir) + install_platlib = os.path.relpath( + install_cmd.install_platlib, self.install_dir) for i, data_files in enumerate(self.data_files): if isinstance(data_files, str): @@ -282,96 +440,89 @@ def run(self): dest = data_files[0].format(install_platlib=install_platlib) self.data_files[i] = dest, data_files[1] - return install_data.run(self) - - -def _check_output(*popenargs, **kwargs): - """subprocess.check_output from python 2.7. - Added here to support building for earlier versions of Python. - """ - process = Popen(stdout=PIPE, *popenargs, **kwargs) - output, unused_err = process.communicate() - retcode = process.poll() - if retcode: - cmd = kwargs.get("args") - if cmd is None: - cmd = popenargs[0] - raise CalledProcessError(retcode, cmd, output=output) - if sys.version_info[0] > 2: - return output.decode("ascii") - return output - + return install_data.install_data.run(self) -def _get_interop_filename(): - """interopXX.cs is auto-generated as part of the build. - For common windows platforms pre-generated files are included - as most windows users won't have Clang installed, which is - required to generate the file. - """ - interop_file = "interop%d%d%s.cs" % (sys.version_info[0], sys.version_info[1], getattr(sys, "abiflags", "")) - return os.path.join("src", "runtime", interop_file) +class InstallPythonnet(install.install): + user_options = install.install.user_options + [ + ('xplat', None, None) + ] + def initialize_options(self): + install.install.initialize_options(self) + self.xplat = None + def finalize_options(self): + install.install.finalize_options(self) -if __name__ == "__main__": - setupdir = os.path.dirname(__file__) - if setupdir: - os.chdir(setupdir) + def run(self): + if self.xplat: + _update_xlat_devtools() + return install.install.run(self) - sources = [] - for ext in (".sln", ".snk", ".config"): - sources.extend(glob("*" + ext)) +class BDistWheelPythonnet(bdist_wheel.bdist_wheel): + user_options = bdist_wheel.bdist_wheel.user_options + [ + ('xplat', None, None) + ] + def initialize_options(self): + bdist_wheel.bdist_wheel.initialize_options(self) + self.xplat = None - for root, dirnames, filenames in os.walk("src"): - for ext in (".cs", ".csproj", ".sln", ".snk", ".config", ".il", ".py", ".c", ".h", ".ico"): - for filename in fnmatch.filter(filenames, "*" + ext): - sources.append(os.path.join(root, filename)) + def finalize_options(self): + bdist_wheel.bdist_wheel.finalize_options(self) - for root, dirnames, filenames in os.walk("tools"): - for ext in (".exe", ".py", ".c", ".h"): - for filename in fnmatch.filter(filenames, "*" + ext): - sources.append(os.path.join(root, filename)) - - setup_requires = [] - interop_file = _get_interop_filename() - if not os.path.exists(interop_file): - setup_requires.append("pycparser") - - setup( - name="pythonnet", - version="2.2.2", - description=".Net and Mono integration for Python", - url='https://pythonnet.github.io/', - license='MIT', - author="The Python for .Net developers", - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: C#', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Operating System :: Microsoft :: Windows', - 'Operating System :: POSIX :: Linux', - 'Operating System :: MacOS :: MacOS X', - ], - ext_modules=[ - Extension("clr", sources=sources) - ], - data_files=[ - ("{install_platlib}", [ - "{build_lib}/Python.Runtime.dll", - "Python.Runtime.dll.config"]), - ], - zip_safe=False, - cmdclass={ - "build_ext": PythonNET_BuildExt, - "install_lib": PythonNET_InstallLib, - "install_data": PythonNET_InstallData, - }, - setup_requires=setup_requires - ) + def run(self): + if self.xplat: + _update_xlat_devtools() + return bdist_wheel.bdist_wheel.run(self) + + ############################################################################### +setupdir = os.path.dirname(__file__) +if setupdir: + os.chdir(setupdir) + +setup_requires = [] +if not os.path.exists(_get_interop_filename()): + setup_requires.append("pycparser") + +setup( + name="pythonnet", + version="2.4.0.dev0", + description=".Net and Mono integration for Python", + url='https://pythonnet.github.io/', + license='MIT', + author="The Python for .Net developers", + author_email="pythondotnet@python.org", + setup_requires=setup_requires, + long_description=_get_long_description(), + ext_modules=[ + Extension("clr", sources=list(_get_source_files())) + ], + data_files=[ + ("{install_platlib}", [ + "{build_lib}/Python.Runtime.dll", + ]), + ], + cmdclass={ + "install": InstallPythonnet, + "build_ext": BuildExtPythonnet, + "install_lib": InstallLibPythonnet, + "install_data": InstallDataPythonnet, + "bdist_wheel": BDistWheelPythonnet + }, + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Programming Language :: C#', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: POSIX :: Linux', + 'Operating System :: MacOS :: MacOS X', + ], + zip_safe=False, +) diff --git a/src/SharedAssemblyInfo.cs b/src/SharedAssemblyInfo.cs new file mode 100644 index 000000000..c164e75d6 --- /dev/null +++ b/src/SharedAssemblyInfo.cs @@ -0,0 +1,28 @@ +using System; +using System.Reflection; +using System.Resources; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("pythonnet")] +[assembly: AssemblyProduct("Python for .NET")] +[assembly: AssemblyCopyright("Copyright (c) 2006-2017 the contributors of the 'Python for .NET' project")] +[assembly: AssemblyTrademark("")] + +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("")] + +[assembly: CLSCompliant(true)] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// Version Information. Keeping it simple. May need to revisit for Nuget +// See: https://codingforsmarties.wordpress.com/2016/01/21/how-to-version-assemblies-destined-for-nuget/ +// AssemblyVersion can only be numeric +[assembly: AssemblyVersion("2.4.0")] diff --git a/src/clrmodule/AssemblyInfo.cs b/src/clrmodule/AssemblyInfo.cs deleted file mode 100644 index 669183255..000000000 --- a/src/clrmodule/AssemblyInfo.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. - -[assembly: AssemblyTitle("clrmodule")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("clrmodule")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. - -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM - -[assembly: Guid("ae10d6a4-55c2-482f-9716-9988e6c169e3")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] - -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/clrmodule/ClrModule.cs b/src/clrmodule/ClrModule.cs index eca411b30..3bb3a533b 100644 --- a/src/clrmodule/ClrModule.cs +++ b/src/clrmodule/ClrModule.cs @@ -21,6 +21,7 @@ // calls are made to indicate what's going on during the load... //============================================================================ using System; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; @@ -37,9 +38,7 @@ public static IntPtr PyInit_clr() public static void initclr() #endif { -#if DEBUG - Console.WriteLine("Attempting to load Python.Runtime using standard binding rules... "); -#endif + DebugPrint("Attempting to load 'Python.Runtime' using standard binding rules."); #if USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN var pythonRuntimePublicKeyTokenData = new byte[] { 0x50, 0x00, 0xfe, 0xa6, 0xcb, 0xa7, 0x02, 0xdd }; #endif @@ -53,7 +52,8 @@ public static void initclr() var pythonRuntimeName = new AssemblyName("Python.Runtime") { #if USE_PYTHON_RUNTIME_VERSION - Version = new Version("4.0.0.1"), + // Has no effect until SNK works. Keep updated anyways. + Version = new Version("2.4.0"), #endif CultureInfo = CultureInfo.InvariantCulture }; @@ -65,12 +65,11 @@ public static void initclr() try { pythonRuntime = Assembly.Load(pythonRuntimeName); -#if DEBUG - Console.WriteLine("Success!"); -#endif + DebugPrint("Success loading 'Python.Runtime' using standard binding rules."); } catch (IOException) { + DebugPrint("'Python.Runtime' not found using standard binding rules."); try { // If the above fails for any reason, we fallback to attempting to load "Python.Runtime.dll" @@ -89,16 +88,13 @@ public static void initclr() throw new InvalidOperationException(executingAssembly.Location); } string pythonRuntimeDllPath = Path.Combine(assemblyDirectory, "Python.Runtime.dll"); -#if DEBUG - Console.WriteLine("Attempting to load Python.Runtime from: '{0}'...", pythonRuntimeDllPath); -#endif + DebugPrint($"Attempting to load Python.Runtime from: '{pythonRuntimeDllPath}'."); pythonRuntime = Assembly.LoadFrom(pythonRuntimeDllPath); + DebugPrint($"Success loading 'Python.Runtime' from: '{pythonRuntimeDllPath}'."); } catch (InvalidOperationException) { -#if DEBUG - Console.WriteLine("Could not load Python.Runtime"); -#endif + DebugPrint("Could not load 'Python.Runtime'."); #if PYTHON3 return IntPtr.Zero; #elif PYTHON2 @@ -117,4 +113,14 @@ public static void initclr() pythonEngineType.InvokeMember("InitExt", BindingFlags.InvokeMethod, null, null, null); #endif } + + /// + /// Substitute for Debug.Writeline(...). Ideally we would use Debug.Writeline + /// but haven't been able to configure the TRACE from within Python. + /// + [Conditional("DEBUG")] + private static void DebugPrint(string str) + { + Console.WriteLine(str); + } } diff --git a/src/clrmodule/Properties/AssemblyInfo.cs b/src/clrmodule/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..939f4171f --- /dev/null +++ b/src/clrmodule/Properties/AssemblyInfo.cs @@ -0,0 +1,11 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("clrmodule")] +[assembly: AssemblyDescription("")] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ae10d6a4-55c2-482f-9716-9988e6c169e3")] diff --git a/src/clrmodule/clrmodule.15.csproj b/src/clrmodule/clrmodule.15.csproj new file mode 100644 index 000000000..2585ffdd2 --- /dev/null +++ b/src/clrmodule/clrmodule.15.csproj @@ -0,0 +1,95 @@ + + + + + + net40 + x64;x86 + DebugMono;DebugMonoPY3;ReleaseMono;ReleaseMonoPY3;DebugWin;DebugWinPY3;ReleaseWin;ReleaseWinPY3 + clrmodule + clrmodule + clrmodule + 2.4.0 + false + false + false + false + false + false + bin\clrmodule.xml + bin\ + false + 1591 + ..\..\ + $(SolutionDir)\bin\ + $(PythonBuildDir)\$(TargetFramework)\ + 6 + prompt + $(PYTHONNET_DEFINE_CONSTANTS) + XPLAT + $(DefineConstants);$(CustomDefineConstants);$(BaseDefineConstants); + $(DefineConstants);TRACE;DEBUG + + + + x86 + + + x64 + + + + false + full + + + true + pdbonly + + + + $(DefineConstants);PYTHON2;TRACE;DEBUG + + + $(DefineConstants);PYTHON2 + + + $(DefineConstants);PYTHON2;TRACE;DEBUG + + + $(DefineConstants);PYTHON2 + + + $(DefineConstants);PYTHON3;TRACE;DEBUG + + + $(DefineConstants);PYTHON3 + + + $(DefineConstants);PYTHON3;TRACE;DEBUG + + + $(DefineConstants);PYTHON3 + + + + + + + + + + + + + + $(TargetPath) + $(TargetDir)$(TargetName).pdb + + + + + + + + diff --git a/src/clrmodule/clrmodule.csproj b/src/clrmodule/clrmodule.csproj index d19646778..6e5ff4966 100644 --- a/src/clrmodule/clrmodule.csproj +++ b/src/clrmodule/clrmodule.csproj @@ -1,107 +1,69 @@ - + Debug - x86 - 8.0.30703 - 2.0 + AnyCPU {86E834DE-1139-4511-96CC-69636A56E7AC} Library - clrmodule clrmodule + clrmodule + bin\clrmodule.xml + bin\ v4.0 - 512 + + 1591 ..\..\ - $(SolutionDir) + $(SolutionDir)\bin\ + Properties + 6 true + prompt - - true - bin\x86\DebugMono\ - TRACE;DEBUG;PYTHON2 - full + x86 - prompt - true - true - false - + + x64 + + true - bin\x64\DebugMono\ - TRACE;DEBUG;PYTHON2 + PYTHON2;TRACE;DEBUG full - x64 - prompt - true - true - false - - bin\x86\ReleaseMono\ + PYTHON2 true pdbonly - x86 - prompt - true - true - false - - bin\x64\ReleaseMono\ + + true + PYTHON2;TRACE;DEBUG + full + + PYTHON2 true pdbonly - x64 - prompt - true - true - false - + true - bin\x86\DebugWin\ - TRACE;DEBUG;PYTHON2 + PYTHON3;TRACE;DEBUG full - x86 - prompt - true - false - false - - - true - bin\x64\DebugWin\ - TRACE;DEBUG;PYTHON2 - full - x64 - prompt - true - true - false - - bin\x86\ReleaseWin\ - PYTHON2 + + PYTHON3 true pdbonly - x86 - prompt - true - true - false - - bin\x64\ReleaseWin\ - PYTHON2 + + true + PYTHON3;TRACE;DEBUG + full + + + PYTHON3 true pdbonly - x64 - prompt - true - true - false @@ -111,8 +73,11 @@ + + + Properties\SharedAssemblyInfo.cs + - diff --git a/src/clrmodule/packages.config b/src/clrmodule/packages.config index 01dd53f14..2a95dc54d 100644 --- a/src/clrmodule/packages.config +++ b/src/clrmodule/packages.config @@ -1,5 +1,4 @@ - diff --git a/src/console/Console.15.csproj b/src/console/Console.15.csproj new file mode 100644 index 000000000..ec5008036 --- /dev/null +++ b/src/console/Console.15.csproj @@ -0,0 +1,94 @@ + + + + net40;netcoreapp2.0 + x64;x86 + DebugMono;DebugMonoPY3;ReleaseMono;ReleaseMonoPY3;DebugWin;DebugWinPY3;ReleaseWin;ReleaseWinPY3 + Exe + nPython + Python.Runtime + nPython + 2.4.0 + false + false + false + false + false + false + bin\ + false + $(OutputPath)\$(AssemblyName).xml + $(OutputPath)\$(TargetFramework)\$(AssemblyName).xml + 1591 + ..\..\ + $(SolutionDir)\bin\ + $(PythonBuildDir)\$(TargetFramework)\ + 6 + python-clear.ico + prompt + $(PYTHONNET_DEFINE_CONSTANTS) + XPLAT + $(DefineConstants);$(CustomDefineConstants);$(BaseDefineConstants); + $(DefineConstants);TRACE;DEBUG + $(NuGetPackageRoot)\microsoft.targetingpack.netframework.v4.5\1.0.1\lib\net45\ + + + x86 + + + x64 + + + + false + full + + + true + pdbonly + + + true + false + full + + + true + true + portable + + + + $(DefineConstants);DEBUG;TRACE + + + $(DefineConstants) + + + + $(PythonManifest) + + + + + + + Properties\SharedAssemblyInfo.cs + + + + + + Python.Runtime.dll + + + + + + + + + + + + diff --git a/src/console/Console.csproj b/src/console/Console.csproj index d2d396341..ea88b6356 100644 --- a/src/console/Console.csproj +++ b/src/console/Console.csproj @@ -5,192 +5,81 @@ AnyCPU {E29DCF0A-5114-4A98-B1DD-71264B6EA349} Exe - false nPython Python.Runtime - OnBuildSuccess - - - - - 3.5 - python-clear.ico - 10.0.0 - 2.0 + bin\nPython.xml + bin\ + v4.0 + + 1591 ..\..\ - $(SolutionDir) - - - True - full - False - bin\Debug\ - DEBUG;TRACE - 4 - - - pdbonly - True - bin\Release\ - TRACE - True - false - 4 - - - True - bin\EmbeddingTest\ - DEBUG;TRACE - full - AnyCPU - 4 - False - - - True - bin\UnitTests\ - DEBUG;TRACE - full - AnyCPU - 4 - False + $(SolutionDir)\bin\ + Properties + 6 + python-clear.ico + prompt - - True - bin\x86\Debug\ - DEBUG;TRACE - full + x86 - true - true - True - 4 - False - False - - True - bin\x86\Release\ - TRACE - True - pdbonly - x86 - false - true - true - 4 + + x64 - - True - bin\x86\EmbeddingTest\ + + true DEBUG;TRACE full - x86 - 4 - False - - True - bin\x86\UnitTests\ - DEBUG;TRACE - full - x86 - false - false - 4 - False + + + + true + pdbonly - - True - bin\DebugMono_x86\ + + true DEBUG;TRACE full - AnyCPU - 4 - False - - True - bin\x86\DebugMono_x86\ - DEBUG;TRACE - full - x86 - true - true - 4 - False + + + + true + pdbonly - - True - bin\x64\Debug\ + + true DEBUG;TRACE full - x64 - true - true - false - 4 - False - - True - bin\x64\Release\ - TRACE - True + + + + true pdbonly - x64 - false - true - true - false - 4 - - - True - bin\x64\EmbeddingTest\ - DEBUG;TRACE - full - x64 - false - false - false - 4 - False - - True - bin\x64\UnitTests\ + + true DEBUG;TRACE full - x64 - false - false - 4 - False - - True - bin\x64\DebugMono_x86\ - DEBUG;TRACE - full - x64 - true - true - false - 4 - False + + + + true + pdbonly $(PythonManifest) - - 3.5 - - + + + Properties\SharedAssemblyInfo.cs + @@ -199,9 +88,6 @@ Python.Runtime.dll - - - {097b4ac0-74e9-4c58-bcf8-c69746ec8271} @@ -209,9 +95,6 @@ - - - diff --git a/src/console/Properties/AssemblyInfo.cs b/src/console/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..081ae0c94 --- /dev/null +++ b/src/console/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Python Console")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyDefaultAlias("python.exe")] diff --git a/src/console/app.config b/src/console/app.config deleted file mode 100644 index e7368c65b..000000000 --- a/src/console/app.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/console/assemblyinfo.cs b/src/console/assemblyinfo.cs deleted file mode 100644 index c7d957326..000000000 --- a/src/console/assemblyinfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Reflection; -using System.Resources; -using System.Runtime.InteropServices; -using System.Security.Permissions; - -[assembly: AssemblyProduct("Python for .NET")] -[assembly: AssemblyVersion("2.4.2.7")] -[assembly: AssemblyTitle("Python Console")] -[assembly: AssemblyDefaultAlias("python.exe")] -[assembly: CLSCompliant(true)] -[assembly: ComVisible(false)] -[assembly: PermissionSet(SecurityAction.RequestMinimum, - Name = "FullTrust")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyCopyright("MIT License")] -[assembly: AssemblyFileVersion("2.0.0.4")] -[assembly: NeutralResourcesLanguage("en")] diff --git a/src/console/pythonconsole.cs b/src/console/pythonconsole.cs index a696f62f6..912e9bb0d 100644 --- a/src/console/pythonconsole.cs +++ b/src/console/pythonconsole.cs @@ -1,14 +1,24 @@ using System; using System.Collections.Generic; +using System.IO; using System.Reflection; using Python.Runtime; namespace Python.Runtime { + /// + /// Example of Embedding Python inside of a .NET program. + /// + /// + /// It has similar functionality to doing `import clr` from within Python, but this does it + /// the other way around; That is, it loads Python inside of .NET program. + /// See https://github.com/pythonnet/pythonnet/issues/358 for more info. + /// public sealed class PythonConsole { +#if NET40 private static AssemblyLoader assemblyLoader = new AssemblyLoader(); - +#endif private PythonConsole() { } @@ -16,9 +26,11 @@ private PythonConsole() [STAThread] public static int Main(string[] args) { + // Only net40 is capable to safely inject python.runtime.dll into resources. +#if NET40 // reference the static assemblyLoader to stop it being optimized away AssemblyLoader a = assemblyLoader; - +#endif string[] cmd = Environment.GetCommandLineArgs(); PythonEngine.Initialize(); @@ -28,11 +40,12 @@ public static int Main(string[] args) return i; } +#if NET40 // Register a callback function to load embedded assemblies. // (Python.Runtime.dll is included as a resource) private sealed class AssemblyLoader { - Dictionary loadedAssemblies; + private Dictionary loadedAssemblies; public AssemblyLoader() { @@ -41,7 +54,7 @@ public AssemblyLoader() AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { string shortName = args.Name.Split(',')[0]; - string resourceName = string.Format("{0}.dll", shortName); + string resourceName = $"{shortName}.dll"; if (loadedAssemblies.ContainsKey(resourceName)) { @@ -49,7 +62,7 @@ public AssemblyLoader() } // looks for the assembly from the resources and load it - using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) + using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) { if (stream != null) { @@ -60,10 +73,10 @@ public AssemblyLoader() return assembly; } } - return null; }; } } +#endif } } diff --git a/src/embed_tests/Program.cs b/src/embed_tests/Program.cs new file mode 100644 index 000000000..b4439e3e4 --- /dev/null +++ b/src/embed_tests/Program.cs @@ -0,0 +1,19 @@ +using System; + +using NUnit.Common; + +using NUnitLite; + +namespace Python.EmbeddingTest +{ + public class Program + { + public static int Main(string[] args) + { + return new AutoRun(typeof(Program).Assembly).Execute( + args, + new ExtendedTextWrapper(Console.Out), + Console.In); + } + } +} diff --git a/src/embed_tests/Python.EmbeddingTest.15.csproj b/src/embed_tests/Python.EmbeddingTest.15.csproj new file mode 100644 index 000000000..92d55a7e0 --- /dev/null +++ b/src/embed_tests/Python.EmbeddingTest.15.csproj @@ -0,0 +1,115 @@ + + + + + net40;netcoreapp2.0 + x64;x86 + DebugMono;DebugMonoPY3;ReleaseMono;ReleaseMonoPY3;DebugWin;DebugWinPY3;ReleaseWin;ReleaseWinPY3 + Exe + false + Python.EmbeddingTest + Python.EmbeddingTest + Python.EmbeddingTest + 2.4.0 + false + false + false + false + bin\ + false + $(OutputPath)\$(AssemblyName).xml + $(OutputPath)\$(TargetFramework)\$(AssemblyName).xml + 1591 + ..\..\ + $(SolutionDir)\bin\ + $(OutputPath)\$(TargetFramework)_publish + 6 + prompt + $(PYTHONNET_DEFINE_CONSTANTS) + XPLAT + $(DefineConstants);$(CustomDefineConstants);$(BaseDefineConstants); + $(DefineConstants);NETCOREAPP + $(DefineConstants);TRACE;DEBUG + $(NuGetPackageRoot)\microsoft.targetingpack.netframework.v4.5\1.0.1\lib\net45\ + + + x86 + + + x64 + + + + false + full + + + true + pdbonly + + + true + false + full + + + true + true + portable + + + + $(DefineConstants);DEBUG;TRACE + + + $(DefineConstants) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(TargetPath) + $(TargetDir)$(TargetName).pdb + + + + + + + + diff --git a/src/embed_tests/Python.EmbeddingTest.csproj b/src/embed_tests/Python.EmbeddingTest.csproj index 24645f1bd..fe02b0526 100644 --- a/src/embed_tests/Python.EmbeddingTest.csproj +++ b/src/embed_tests/Python.EmbeddingTest.csproj @@ -1,170 +1,107 @@ - + Debug AnyCPU {4165C59D-2822-499F-A6DB-EACA4C331EB5} Library - false Python.EmbeddingTest Python.EmbeddingTest - OnBuildSuccess - - - - - 3.5 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - 10.0.0 - 2.0 + bin\Python.EmbeddingTest.xml + bin\ + v4.0 + + 1591 ..\..\ - $(SolutionDir) + $(SolutionDir)\bin\ + 6 true + prompt - - true - bin\x86\DebugMono\ - DEBUG;TRACE - full + x86 - prompt - true - true - false - + + x64 + + true - bin\x64\DebugMono\ DEBUG;TRACE full - x64 - prompt - true - true - false - - bin\x86\ReleaseMono\ + true pdbonly - x86 - prompt - true - true - false - - bin\x64\ReleaseMono\ + + true + DEBUG;TRACE + full + + true pdbonly - x64 - prompt - true - true - false - - - true - bin\x86\DebugWin\ - DEBUG;TRACE - full - x86 - prompt - true - false - false - + true - bin\x64\DebugWin\ DEBUG;TRACE full - x64 - prompt - true - true - false - - bin\x86\ReleaseWin\ + true pdbonly - x86 - prompt - true - true - false - - bin\x64\ReleaseWin\ + + true + DEBUG;TRACE + full + + true pdbonly - x64 - prompt - true - true - false - - - 3.5 - - - ..\..\packages\NUnit.2.6.2\lib\nunit.framework.dll + + + ..\..\packages\NUnit.3.7.1\lib\net40\nunit.framework.dll + - + - - Code - - - - - - - False - .NET Framework 2.0 %28x86%29 - true - - - False - .NET Framework 3.0 %28x86%29 - false - - - False - .NET Framework 3.5 - false - + + + + + + + + + + + + + + + + + + + + @@ -172,16 +109,16 @@ Python.Runtime + + + - - - $(TargetPath) $(TargetDir)$(TargetName).pdb - + - + \ No newline at end of file diff --git a/src/embed_tests/TestConverter.cs b/src/embed_tests/TestConverter.cs new file mode 100644 index 000000000..346c8afdc --- /dev/null +++ b/src/embed_tests/TestConverter.cs @@ -0,0 +1,48 @@ +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestConverter + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public void TestConvertSingleToManaged( + [Values(float.PositiveInfinity, float.NegativeInfinity, float.MinValue, float.MaxValue, float.NaN, + float.Epsilon)] float testValue) + { + var pyFloat = new PyFloat(testValue); + + object convertedValue; + var converted = Converter.ToManaged(pyFloat.Handle, typeof(float), out convertedValue, false); + + Assert.IsTrue(converted); + Assert.IsTrue(((float) convertedValue).Equals(testValue)); + } + + [Test] + public void TestConvertDoubleToManaged( + [Values(double.PositiveInfinity, double.NegativeInfinity, double.MinValue, double.MaxValue, double.NaN, + double.Epsilon)] double testValue) + { + var pyFloat = new PyFloat(testValue); + + object convertedValue; + var converted = Converter.ToManaged(pyFloat.Handle, typeof(double), out convertedValue, false); + + Assert.IsTrue(converted); + Assert.IsTrue(((double) convertedValue).Equals(testValue)); + } + } +} diff --git a/src/embed_tests/TestCustomMarshal.cs b/src/embed_tests/TestCustomMarshal.cs new file mode 100644 index 000000000..5860857a3 --- /dev/null +++ b/src/embed_tests/TestCustomMarshal.cs @@ -0,0 +1,35 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestCustomMarshal + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public static void GetManagedStringTwice() + { + const string expected = "FooBar"; + + IntPtr op = Runtime.Runtime.PyUnicode_FromString(expected); + string s1 = Runtime.Runtime.GetManagedString(op); + string s2 = Runtime.Runtime.GetManagedString(op); + + Assert.AreEqual(1, Runtime.Runtime.Refcount(op)); + Assert.AreEqual(expected, s1); + Assert.AreEqual(expected, s2); + } + } +} diff --git a/src/embed_tests/TestExample.cs b/src/embed_tests/TestExample.cs new file mode 100644 index 000000000..671f9e33d --- /dev/null +++ b/src/embed_tests/TestExample.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestExample + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public void TestReadme() + { + dynamic np; + try + { + np = Py.Import("numpy"); + } + catch (PythonException) + { + Assert.Inconclusive("Numpy or dependency not installed"); + return; + } + + Assert.AreEqual("1.0", np.cos(np.pi * 2).ToString()); + + dynamic sin = np.sin; + StringAssert.StartsWith("-0.95892", sin(5).ToString()); + + double c = np.cos(5) + sin(5); + Assert.AreEqual(-0.675262, c, 0.01); + + dynamic a = np.array(new List { 1, 2, 3 }); + Assert.AreEqual("float64", a.dtype.ToString()); + + dynamic b = np.array(new List { 6, 5, 4 }, Py.kw("dtype", np.int32)); + Assert.AreEqual("int32", b.dtype.ToString()); + + Assert.AreEqual("[ 6. 10. 12.]", (a * b).ToString().Replace(" ", " ")); + } + } +} diff --git a/src/embed_tests/TestNamedArguments.cs b/src/embed_tests/TestNamedArguments.cs new file mode 100644 index 000000000..1d7076956 --- /dev/null +++ b/src/embed_tests/TestNamedArguments.cs @@ -0,0 +1,64 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestNamedArguments + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + /// + /// Test named arguments support through Py.kw method + /// + [Test] + public void TestKeywordArgs() + { + dynamic a = CreateTestClass(); + var result = (int)a.Test3(2, Py.kw("a4", 8)); + + Assert.AreEqual(12, result); + } + + + /// + /// Test keyword arguments with .net named arguments + /// + [Test] + public void TestNamedArgs() + { + dynamic a = CreateTestClass(); + var result = (int)a.Test3(2, a4: 8); + + Assert.AreEqual(12, result); + } + + + + private static PyObject CreateTestClass() + { + var locals = new PyDict(); + + PythonEngine.Exec(@" +class cmTest3: + def Test3(self, a1 = 1, a2 = 1, a3 = 1, a4 = 1): + return a1 + a2 + a3 + a4 + +a = cmTest3() +", null, locals.Handle); + + return locals.GetItem("a"); + } + + } +} diff --git a/src/embed_tests/TestPyAnsiString.cs b/src/embed_tests/TestPyAnsiString.cs new file mode 100644 index 000000000..9ba7d6cc6 --- /dev/null +++ b/src/embed_tests/TestPyAnsiString.cs @@ -0,0 +1,96 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestPyAnsiString + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public void TestStringCtor() + { + const string expected = "foo"; + var actual = new PyAnsiString(expected); + Assert.AreEqual(expected, actual.ToString()); + } + + [Test] + public void TestEmptyStringCtor() + { + const string expected = ""; + var actual = new PyAnsiString(expected); + Assert.AreEqual(expected, actual.ToString()); + } + + [Test] + public void TestPyObjectCtor() + { + const string expected = "Foo"; + + var t = new PyAnsiString(expected); + var actual = new PyAnsiString(t); + + Assert.AreEqual(expected, actual.ToString()); + } + + [Test] + public void TestBadPyObjectCtor() + { + var t = new PyInt(5); + PyAnsiString actual = null; + + var ex = Assert.Throws(() => actual = new PyAnsiString(t)); + + StringAssert.StartsWith("object is not a string", ex.Message); + Assert.IsNull(actual); + } + + [Test] + public void TestCtorPtr() + { + const string expected = "foo"; + + var t = new PyAnsiString(expected); + var actual = new PyAnsiString(t.Handle); + + Assert.AreEqual(expected, actual.ToString()); + } + + [Test] + public void IsStringTrue() + { + var t = new PyAnsiString("foo"); + + Assert.True(PyAnsiString.IsStringType(t)); + } + + [Test] + public void IsStringFalse() + { + var t = new PyInt(5); + + Assert.False(PyAnsiString.IsStringType(t)); + } + + [Test] + [Ignore("Ambiguous behavior between PY2/PY3")] + public void TestUnicode() + { + const string expected = "foo\u00e9"; + PyObject actual = new PyAnsiString(expected); + Assert.AreEqual(expected, actual.ToString()); + } + } +} diff --git a/src/embed_tests/TestPyFloat.cs b/src/embed_tests/TestPyFloat.cs new file mode 100644 index 000000000..f2c85a77f --- /dev/null +++ b/src/embed_tests/TestPyFloat.cs @@ -0,0 +1,138 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + /// + /// PyFloat implementation isn't complete, thus tests aren't complete. + /// + public class TestPyFloat + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public void IntPtrCtor() + { + var i = new PyFloat(1); + var ii = new PyFloat(i.Handle); + Assert.AreEqual(i.Handle, ii.Handle); + } + + [Test] + public void FloatCtor() + { + const float a = 4.5F; + var i = new PyFloat(a); + Assert.True(PyFloat.IsFloatType(i)); + // Assert.Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void PyObjectCtorGood() + { + var i = new PyFloat(5); + var a = new PyFloat(i); + Assert.True(PyFloat.IsFloatType(a)); + // Assert.Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void PyObjectCtorBad() + { + var i = new PyString("Foo"); + PyFloat a = null; + + var ex = Assert.Throws(() => a = new PyFloat(i)); + + StringAssert.StartsWith("object is not a float", ex.Message); + Assert.IsNull(a); + } + + [Test] + public void DoubleCtor() + { + const double a = 4.5; + var i = new PyFloat(a); + Assert.True(PyFloat.IsFloatType(i)); + // Assert.Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void StringIntCtor() + { + const string a = "5"; + var i = new PyFloat(a); + Assert.True(PyFloat.IsFloatType(i)); + // Assert.Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void StringDoubleCtor() + { + const string a = "4.5"; + var i = new PyFloat(a); + Assert.True(PyFloat.IsFloatType(i)); + // Assert.Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void StringBadCtor() + { + const string i = "Foo"; + PyFloat a = null; + + var ex = Assert.Throws(() => a = new PyFloat(i)); + + StringAssert.StartsWith("ValueError : could not convert string to float", ex.Message); + Assert.IsNull(a); + } + + [Test] + public void IsFloatTrue() + { + const double a = 4.5; + var i = new PyFloat(a); + Assert.True(PyFloat.IsFloatType(i)); + } + + [Test] + public void IsFloatFalse() + { + var i = new PyString("Foo"); + Assert.False(PyFloat.IsFloatType(i)); + } + + [Test] + public void AsFloatGood() + { + const double a = 4.5; + var i = new PyFloat(a); + PyFloat s = PyFloat.AsFloat(i); + + Assert.True(PyFloat.IsFloatType(s)); + // Assert.Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void AsFloatBad() + { + var s = new PyString("Foo"); + PyFloat a = null; + + var ex = Assert.Throws(() => a = PyFloat.AsFloat(s)); + StringAssert.StartsWith("ValueError : could not convert string to float", ex.Message); + Assert.IsNull(a); + } + } +} diff --git a/src/embed_tests/TestPyInt.cs b/src/embed_tests/TestPyInt.cs new file mode 100644 index 000000000..4117336d8 --- /dev/null +++ b/src/embed_tests/TestPyInt.cs @@ -0,0 +1,190 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestPyInt + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public void TestCtorInt() + { + const int i = 5; + var a = new PyInt(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorUInt() + { + const uint i = 5; + var a = new PyInt(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorLong() + { + const long i = 5; + var a = new PyInt(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorULong() + { + const ulong i = 5; + var a = new PyInt(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorShort() + { + const short i = 5; + var a = new PyInt(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorUShort() + { + const ushort i = 5; + var a = new PyInt(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorByte() + { + const byte i = 5; + var a = new PyInt(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorSByte() + { + const sbyte i = 5; + var a = new PyInt(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorPtr() + { + var i = new PyInt(5); + var a = new PyInt(i.Handle); + Assert.AreEqual(5, a.ToInt32()); + } + + [Test] + public void TestCtorPyObject() + { + var i = new PyInt(5); + var a = new PyInt(i); + Assert.AreEqual(5, a.ToInt32()); + } + + [Test] + public void TestCtorBadPyObject() + { + var i = new PyString("Foo"); + PyInt a = null; + + var ex = Assert.Throws(() => a = new PyInt(i)); + + StringAssert.StartsWith("object is not an int", ex.Message); + Assert.IsNull(a); + } + + [Test] + public void TestCtorString() + { + const string i = "5"; + var a = new PyInt(i); + Assert.AreEqual(5, a.ToInt32()); + } + + [Test] + public void TestCtorBadString() + { + const string i = "Foo"; + PyInt a = null; + + var ex = Assert.Throws(() => a = new PyInt(i)); + + StringAssert.StartsWith("ValueError : invalid literal for int", ex.Message); + Assert.IsNull(a); + } + + [Test] + public void TestIsIntTypeTrue() + { + var i = new PyInt(5); + Assert.True(PyInt.IsIntType(i)); + } + + [Test] + public void TestIsIntTypeFalse() + { + var s = new PyString("Foo"); + Assert.False(PyInt.IsIntType(s)); + } + + [Test] + public void TestAsIntGood() + { + var i = new PyInt(5); + var a = PyInt.AsInt(i); + Assert.AreEqual(5, a.ToInt32()); + } + + [Test] + public void TestAsIntBad() + { + var s = new PyString("Foo"); + PyInt a = null; + + var ex = Assert.Throws(() => a = PyInt.AsInt(s)); + StringAssert.StartsWith("ValueError : invalid literal for int", ex.Message); + Assert.IsNull(a); + } + + [Test] + public void TestConvertToInt32() + { + var a = new PyInt(5); + Assert.IsInstanceOf(typeof(int), a.ToInt32()); + Assert.AreEqual(5, a.ToInt32()); + } + + [Test] + public void TestConvertToInt16() + { + var a = new PyInt(5); + Assert.IsInstanceOf(typeof(short), a.ToInt16()); + Assert.AreEqual(5, a.ToInt16()); + } + + [Test] + public void TestConvertToInt64() + { + var a = new PyInt(5); + Assert.IsInstanceOf(typeof(long), a.ToInt64()); + Assert.AreEqual(5, a.ToInt64()); + } + } +} diff --git a/src/embed_tests/TestPyList.cs b/src/embed_tests/TestPyList.cs new file mode 100644 index 000000000..e9acfbb45 --- /dev/null +++ b/src/embed_tests/TestPyList.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestPyList + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public void TestStringIsListType() + { + var s = new PyString("foo"); + Assert.False(PyList.IsListType(s)); + } + + [Test] + public void TestListIsListType() + { + var s = new PyList(); + Assert.True(PyList.IsListType(s)); + } + + [Test] + public void TestStringAsListType() + { + var i = new PyInt(5); + PyList t = null; + + var ex = Assert.Throws(() => t = PyList.AsList(i)); + + Assert.AreEqual("TypeError : 'int' object is not iterable", ex.Message); + Assert.IsNull(t); + } + + [Test] + public void TestListAsListType() + { + var l = new PyList(); + PyList t = PyList.AsList(l); + + Assert.IsNotNull(t); + Assert.IsInstanceOf(typeof(PyList), t); + } + + [Test] + public void TestEmptyCtor() + { + var s = new PyList(); + + Assert.IsInstanceOf(typeof(PyList), s); + Assert.AreEqual(0, s.Length()); + } + + [Test] + public void TestPyObjectArrayCtor() + { + var ai = new PyObject[] {new PyInt(3), new PyInt(2), new PyInt(1) }; + var s = new PyList(ai); + + Assert.IsInstanceOf(typeof(PyList), s); + Assert.AreEqual(3, s.Length()); + Assert.AreEqual("3", s[0].ToString()); + Assert.AreEqual("2", s[1].ToString()); + Assert.AreEqual("1", s[2].ToString()); + } + + [Test] + public void TestPyObjectCtor() + { + var a = new PyList(); + var s = new PyList(a); + + Assert.IsInstanceOf(typeof(PyList), s); + Assert.AreEqual(0, s.Length()); + } + + [Test] + public void TestBadPyObjectCtor() + { + var i = new PyInt(5); + PyList t = null; + + var ex = Assert.Throws(() => t = new PyList(i)); + + Assert.AreEqual("object is not a list", ex.Message); + Assert.IsNull(t); + } + + [Test] + public void TestAppend() + { + var ai = new PyObject[] { new PyInt(3), new PyInt(2), new PyInt(1) }; + var s = new PyList(ai); + s.Append(new PyInt(4)); + + Assert.AreEqual(4, s.Length()); + Assert.AreEqual("4", s[3].ToString()); + } + + [Test] + public void TestInsert() + { + var ai = new PyObject[] { new PyInt(3), new PyInt(2), new PyInt(1) }; + var s = new PyList(ai); + s.Insert(0, new PyInt(4)); + + Assert.AreEqual(4, s.Length()); + Assert.AreEqual("4", s[0].ToString()); + } + + [Test] + public void TestReverse() + { + var ai = new PyObject[] { new PyInt(3), new PyInt(1), new PyInt(2) }; + var s = new PyList(ai); + + s.Reverse(); + + Assert.AreEqual(3, s.Length()); + Assert.AreEqual("2", s[0].ToString()); + Assert.AreEqual("1", s[1].ToString()); + Assert.AreEqual("3", s[2].ToString()); + } + + [Test] + public void TestSort() + { + var ai = new PyObject[] { new PyInt(3), new PyInt(1), new PyInt(2) }; + var s = new PyList(ai); + + s.Sort(); + + Assert.AreEqual(3, s.Length()); + Assert.AreEqual("1", s[0].ToString()); + Assert.AreEqual("2", s[1].ToString()); + Assert.AreEqual("3", s[2].ToString()); + } + + [Test] + public void TestOnPyList() + { + var list = new PyList(); + + list.Append(new PyString("foo")); + list.Append(new PyString("bar")); + list.Append(new PyString("baz")); + var result = new List(); + foreach (PyObject item in list) + { + result.Add(item.ToString()); + } + + Assert.AreEqual(3, result.Count); + Assert.AreEqual("foo", result[0]); + Assert.AreEqual("bar", result[1]); + Assert.AreEqual("baz", result[2]); + } + } +} diff --git a/src/embed_tests/TestPyLong.cs b/src/embed_tests/TestPyLong.cs new file mode 100644 index 000000000..fe3e13ef5 --- /dev/null +++ b/src/embed_tests/TestPyLong.cs @@ -0,0 +1,206 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestPyLong + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public void TestToInt64() + { + long largeNumber = 8L * 1024L * 1024L * 1024L; // 8 GB + var pyLargeNumber = new PyLong(largeNumber); + Assert.AreEqual(largeNumber, pyLargeNumber.ToInt64()); + } + + [Test] + public void TestCtorInt() + { + const int i = 5; + var a = new PyLong(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorUInt() + { + const uint i = 5; + var a = new PyLong(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorLong() + { + const long i = 5; + var a = new PyLong(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorULong() + { + const ulong i = 5; + var a = new PyLong(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorShort() + { + const short i = 5; + var a = new PyLong(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorUShort() + { + const ushort i = 5; + var a = new PyLong(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorByte() + { + const byte i = 5; + var a = new PyLong(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorSByte() + { + const sbyte i = 5; + var a = new PyLong(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorDouble() + { + double i = 5.0; + var a = new PyLong(i); + Assert.AreEqual(i, a.ToInt32()); + } + + [Test] + public void TestCtorPtr() + { + var i = new PyLong(5); + var a = new PyLong(i.Handle); + Assert.AreEqual(5, a.ToInt32()); + } + + [Test] + public void TestCtorPyObject() + { + var i = new PyLong(5); + var a = new PyLong(i); + Assert.AreEqual(5, a.ToInt32()); + } + + [Test] + public void TestCtorBadPyObject() + { + var i = new PyString("Foo"); + PyLong a = null; + + var ex = Assert.Throws(() => a = new PyLong(i)); + + StringAssert.StartsWith("object is not a long", ex.Message); + Assert.IsNull(a); + } + + [Test] + public void TestCtorString() + { + const string i = "5"; + var a = new PyLong(i); + Assert.AreEqual(5, a.ToInt32()); + } + + [Test] + public void TestCtorBadString() + { + const string i = "Foo"; + PyLong a = null; + + var ex = Assert.Throws(() => a = new PyLong(i)); + + StringAssert.StartsWith("ValueError : invalid literal", ex.Message); + Assert.IsNull(a); + } + + [Test] + public void TestIsIntTypeTrue() + { + var i = new PyLong(5); + Assert.True(PyLong.IsLongType(i)); + } + + [Test] + public void TestIsLongTypeFalse() + { + var s = new PyString("Foo"); + Assert.False(PyLong.IsLongType(s)); + } + + [Test] + public void TestAsLongGood() + { + var i = new PyLong(5); + var a = PyLong.AsLong(i); + Assert.AreEqual(5, a.ToInt32()); + } + + [Test] + public void TestAsLongBad() + { + var s = new PyString("Foo"); + PyLong a = null; + + var ex = Assert.Throws(() => a = PyLong.AsLong(s)); + StringAssert.StartsWith("ValueError : invalid literal", ex.Message); + Assert.IsNull(a); + } + + [Test] + public void TestConvertToInt32() + { + var a = new PyLong(5); + Assert.IsInstanceOf(typeof(int), a.ToInt32()); + Assert.AreEqual(5, a.ToInt32()); + } + + [Test] + public void TestConvertToInt16() + { + var a = new PyLong(5); + Assert.IsInstanceOf(typeof(short), a.ToInt16()); + Assert.AreEqual(5, a.ToInt16()); + } + + [Test] + public void TestConvertToInt64() + { + var a = new PyLong(5); + Assert.IsInstanceOf(typeof(long), a.ToInt64()); + Assert.AreEqual(5, a.ToInt64()); + } + } +} diff --git a/src/embed_tests/TestPyNumber.cs b/src/embed_tests/TestPyNumber.cs new file mode 100644 index 000000000..0261c15c1 --- /dev/null +++ b/src/embed_tests/TestPyNumber.cs @@ -0,0 +1,35 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestPyNumber + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public void IsNumberTypeTrue() + { + var i = new PyInt(1); + Assert.True(PyNumber.IsNumberType(i)); + } + + [Test] + public void IsNumberTypeFalse() + { + var s = new PyString("Foo"); + Assert.False(PyNumber.IsNumberType(s)); + } + } +} diff --git a/src/embed_tests/TestPyScope.cs b/src/embed_tests/TestPyScope.cs new file mode 100644 index 000000000..49c15a3a1 --- /dev/null +++ b/src/embed_tests/TestPyScope.cs @@ -0,0 +1,372 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class PyScopeTest + { + private PyScope ps; + + [SetUp] + public void SetUp() + { + using (Py.GIL()) + { + ps = Py.CreateScope("test"); + } + } + + [TearDown] + public void Dispose() + { + using (Py.GIL()) + { + ps.Dispose(); + ps = null; + } + } + + /// + /// Eval a Python expression and obtain its return value. + /// + [Test] + public void TestEval() + { + using (Py.GIL()) + { + ps.Set("a", 1); + var result = ps.Eval("a + 2"); + Assert.AreEqual(3, result); + } + } + + /// + /// Exec Python statements and obtain the variables created. + /// + [Test] + public void TestExec() + { + using (Py.GIL()) + { + ps.Set("bb", 100); //declare a global variable + ps.Set("cc", 10); //declare a local variable + ps.Exec("aa = bb + cc + 3"); + var result = ps.Get("aa"); + Assert.AreEqual(113, result); + } + } + + /// + /// Compile an expression into an ast object; + /// Execute the ast and obtain its return value. + /// + [Test] + public void TestCompileExpression() + { + using (Py.GIL()) + { + ps.Set("bb", 100); //declare a global variable + ps.Set("cc", 10); //declare a local variable + PyObject script = PythonEngine.Compile("bb + cc + 3", "", RunFlagType.Eval); + var result = ps.Execute(script); + Assert.AreEqual(113, result); + } + } + + /// + /// Compile Python statements into an ast object; + /// Execute the ast; + /// Obtain the local variables created. + /// + [Test] + public void TestCompileStatements() + { + using (Py.GIL()) + { + ps.Set("bb", 100); //declare a global variable + ps.Set("cc", 10); //declare a local variable + PyObject script = PythonEngine.Compile("aa = bb + cc + 3", "", RunFlagType.File); + ps.Execute(script); + var result = ps.Get("aa"); + Assert.AreEqual(113, result); + } + } + + /// + /// Create a function in the scope, then the function can read variables in the scope. + /// It cannot write the variables unless it uses the 'global' keyword. + /// + [Test] + public void TestScopeFunction() + { + using (Py.GIL()) + { + ps.Set("bb", 100); + ps.Set("cc", 10); + ps.Exec( + "def func1():\n" + + " bb = cc + 10\n"); + dynamic func1 = ps.Get("func1"); + func1(); //call the function, it can be called any times + var result = ps.Get("bb"); + Assert.AreEqual(100, result); + + ps.Set("bb", 100); + ps.Set("cc", 10); + ps.Exec( + "def func2():\n" + + " global bb\n" + + " bb = cc + 10\n"); + dynamic func2 = ps.Get("func2"); + func2(); + result = ps.Get("bb"); + Assert.AreEqual(20, result); + } + } + + /// + /// Create a class in the scope, the class can read variables in the scope. + /// Its methods can write the variables with the help of 'global' keyword. + /// + [Test] + public void TestScopeClass() + { + using (Py.GIL()) + { + dynamic _ps = ps; + _ps.bb = 100; + ps.Exec( + "class Class1():\n" + + " def __init__(self, value):\n" + + " self.value = value\n" + + " def call(self, arg):\n" + + " return self.value + bb + arg\n" + //use scope variables + " def update(self, arg):\n" + + " global bb\n" + + " bb = self.value + arg\n" //update scope variable + ); + dynamic obj1 = _ps.Class1(20); + var result = obj1.call(10).As(); + Assert.AreEqual(130, result); + + obj1.update(10); + result = ps.Get("bb"); + Assert.AreEqual(30, result); + } + } + + /// + /// Import a python module into the session. + /// Equivalent to the Python "import" statement. + /// + [Test] + public void TestImportModule() + { + using (Py.GIL()) + { + dynamic sys = ps.Import("sys"); + Assert.IsTrue(ps.Contains("sys")); + + ps.Exec("sys.attr1 = 2"); + var value1 = ps.Eval("sys.attr1"); + var value2 = sys.attr1.As(); + Assert.AreEqual(2, value1); + Assert.AreEqual(2, value2); + + //import as + ps.Import("sys", "sys1"); + Assert.IsTrue(ps.Contains("sys1")); + } + } + + /// + /// Create a scope and import variables from a scope, + /// exec Python statements in the scope then discard it. + /// + [Test] + public void TestImportScope() + { + using (Py.GIL()) + { + ps.Set("bb", 100); + ps.Set("cc", 10); + + using (var scope = Py.CreateScope()) + { + scope.Import(ps, "ps"); + scope.Exec("aa = ps.bb + ps.cc + 3"); + var result = scope.Get("aa"); + Assert.AreEqual(113, result); + } + + Assert.IsFalse(ps.Contains("aa")); + } + } + + /// + /// Create a scope and import variables from a scope, + /// exec Python statements in the scope then discard it. + /// + [Test] + public void TestImportAllFromScope() + { + using (Py.GIL()) + { + ps.Set("bb", 100); + ps.Set("cc", 10); + + using (var scope = ps.NewScope()) + { + scope.Exec("aa = bb + cc + 3"); + var result = scope.Get("aa"); + Assert.AreEqual(113, result); + } + + Assert.IsFalse(ps.Contains("aa")); + } + } + + /// + /// Create a scope and import variables from a scope, + /// call the function imported. + /// + [Test] + public void TestImportScopeFunction() + { + using (Py.GIL()) + { + ps.Set("bb", 100); + ps.Set("cc", 10); + ps.Exec( + "def func1():\n" + + " return cc + bb\n"); + + using (PyScope scope = ps.NewScope()) + { + //'func1' is imported from the origion scope + scope.Exec( + "def func2():\n" + + " return func1() - cc - bb\n"); + dynamic func2 = scope.Get("func2"); + + var result1 = func2().As(); + Assert.AreEqual(0, result1); + + scope.Set("cc", 20);//it has no effect on the globals of 'func1' + var result2 = func2().As(); + Assert.AreEqual(-10, result2); + scope.Set("cc", 10); //rollback + + ps.Set("cc", 20); + var result3 = func2().As(); + Assert.AreEqual(10, result3); + ps.Set("cc", 10); //rollback + } + } + } + + /// + /// Import a python module into the session with a new name. + /// Equivalent to the Python "import .. as .." statement. + /// + [Test] + public void TestImportScopeByName() + { + using (Py.GIL()) + { + ps.Set("bb", 100); + + using (var scope = Py.CreateScope()) + { + scope.ImportAll("test"); + //scope.ImportModule("test"); + + Assert.IsTrue(scope.Contains("bb")); + } + } + } + + /// + /// Use the locals() and globals() method just like in python module + /// + [Test] + public void TestVariables() + { + (ps.Variables() as dynamic)["ee"] = new PyInt(200); + var a0 = ps.Get("ee"); + Assert.AreEqual(200, a0); + + ps.Exec("locals()['ee'] = 210"); + var a1 = ps.Get("ee"); + Assert.AreEqual(210, a1); + + ps.Exec("globals()['ee'] = 220"); + var a2 = ps.Get("ee"); + Assert.AreEqual(220, a2); + + using (var item = ps.Variables()) + { + item["ee"] = new PyInt(230); + } + var a3 = ps.Get("ee"); + Assert.AreEqual(230, a3); + } + + /// + /// Share a pyscope by multiple threads. + /// + [Test] + public void TestThread() + { + //After the proposal here https://github.com/pythonnet/pythonnet/pull/419 complished, + //the BeginAllowThreads statement blow and the last EndAllowThreads statement + //should be removed. + dynamic _ps = ps; + var ts = PythonEngine.BeginAllowThreads(); + using (Py.GIL()) + { + _ps.res = 0; + _ps.bb = 100; + _ps.th_cnt = 0; + //add function to the scope + //can be call many times, more efficient than ast + ps.Exec( + "def update():\n" + + " global res, th_cnt\n" + + " res += bb + 1\n" + + " th_cnt += 1\n" + ); + } + int th_cnt = 3; + for (int i =0; i< th_cnt; i++) + { + System.Threading.Thread th = new System.Threading.Thread(()=> + { + using (Py.GIL()) + { + //ps.GetVariable("update")(); //call the scope function dynamicly + _ps.update(); + } + }); + th.Start(); + } + //equivalent to Thread.Join, make the main thread join the GIL competition + int cnt = 0; + while(cnt != th_cnt) + { + using (Py.GIL()) + { + cnt = ps.Get("th_cnt"); + } + System.Threading.Thread.Sleep(10); + } + using (Py.GIL()) + { + var result = ps.Get("res"); + Assert.AreEqual(101* th_cnt, result); + } + PythonEngine.EndAllowThreads(ts); + } + } +} diff --git a/src/embed_tests/TestPySequence.cs b/src/embed_tests/TestPySequence.cs new file mode 100644 index 000000000..1e3ebf144 --- /dev/null +++ b/src/embed_tests/TestPySequence.cs @@ -0,0 +1,97 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestPySequence + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public void TestIsSequenceTrue() + { + var t = new PyString("FooBar"); + Assert.True(PySequence.IsSequenceType(t)); + } + + [Test] + public void TestIsSequenceFalse() + { + var t = new PyInt(5); + Assert.False(PySequence.IsSequenceType(t)); + } + + [Test] + public void TestGetSlice() + { + var t = new PyString("FooBar"); + + PyObject s = t.GetSlice(0, 3); + Assert.AreEqual("Foo", s.ToString()); + + PyObject s2 = t.GetSlice(3, 6); + Assert.AreEqual("Bar", s2.ToString()); + + PyObject s3 = t.GetSlice(0, 6); + Assert.AreEqual("FooBar", s3.ToString()); + + PyObject s4 = t.GetSlice(0, 12); + Assert.AreEqual("FooBar", s4.ToString()); + } + + [Test] + public void TestConcat() + { + var t1 = new PyString("Foo"); + var t2 = new PyString("Bar"); + + PyObject actual = t1.Concat(t2); + + Assert.AreEqual("FooBar", actual.ToString()); + } + + [Test] + public void TestRepeat() + { + var t1 = new PyString("Foo"); + + PyObject actual = t1.Repeat(3); + Assert.AreEqual("FooFooFoo", actual.ToString()); + + // On 32 bit system this argument should be int, but on the 64 bit system this should be long value. + // This works on the Framework 4.0 accidentally, it should produce out of memory! + // actual = t1.Repeat(-3); + // Assert.AreEqual("", actual.ToString()); + } + + [Test] + public void TestContains() + { + var t1 = new PyString("FooBar"); + + Assert.True(t1.Contains(new PyString("a"))); + Assert.False(t1.Contains(new PyString("z"))); + } + + [Test] + public void TestIndex() + { + var t1 = new PyString("FooBar"); + + Assert.AreEqual(4, t1.Index(new PyString("a"))); + Assert.AreEqual(5, t1.Index(new PyString("r"))); + Assert.AreEqual(-1, t1.Index(new PyString("z"))); + } + } +} diff --git a/src/embed_tests/TestPyString.cs b/src/embed_tests/TestPyString.cs new file mode 100644 index 000000000..9d1cdb0e9 --- /dev/null +++ b/src/embed_tests/TestPyString.cs @@ -0,0 +1,97 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestPyString + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public void TestStringCtor() + { + const string expected = "foo"; + var actual = new PyString(expected); + Assert.AreEqual(expected, actual.ToString()); + } + + [Test] + public void TestEmptyStringCtor() + { + const string expected = ""; + var actual = new PyString(expected); + Assert.AreEqual(expected, actual.ToString()); + } + + [Test] + [Ignore("Ambiguous behavior between PY2/PY3. Needs remapping")] + public void TestPyObjectCtor() + { + const string expected = "Foo"; + + var t = new PyString(expected); + var actual = new PyString(t); + + Assert.AreEqual(expected, actual.ToString()); + } + + [Test] + public void TestBadPyObjectCtor() + { + var t = new PyInt(5); + PyString actual = null; + + var ex = Assert.Throws(() => actual = new PyString(t)); + + StringAssert.StartsWith("object is not a string", ex.Message); + Assert.IsNull(actual); + } + + [Test] + public void TestCtorPtr() + { + const string expected = "foo"; + + var t = new PyString(expected); + var actual = new PyString(t.Handle); + + Assert.AreEqual(expected, actual.ToString()); + } + + [Test] + [Ignore("Ambiguous behavior between PY2/PY3. Needs remapping")] + public void IsStringTrue() + { + var t = new PyString("foo"); + + Assert.True(PyString.IsStringType(t)); + } + + [Test] + public void IsStringFalse() + { + var t = new PyInt(5); + + Assert.False(PyString.IsStringType(t)); + } + + [Test] + public void TestUnicode() + { + const string expected = "foo\u00e9"; + PyObject actual = new PyString(expected); + Assert.AreEqual(expected, actual.ToString()); + } + } +} diff --git a/src/embed_tests/TestPyTuple.cs b/src/embed_tests/TestPyTuple.cs new file mode 100644 index 000000000..362251049 --- /dev/null +++ b/src/embed_tests/TestPyTuple.cs @@ -0,0 +1,171 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestPyTuple + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + /// + /// Test IsTupleType without having to Initialize a tuple. + /// PyTuple constructor use IsTupleType. This decouples the tests. + /// + [Test] + public void TestStringIsTupleType() + { + var s = new PyString("foo"); + Assert.False(PyTuple.IsTupleType(s)); + } + + /// + /// Test IsTupleType with Tuple. + /// + [Test] + public void TestPyTupleIsTupleType() + { + var t = new PyTuple(); + Assert.True(PyTuple.IsTupleType(t)); + } + + [Test] + public void TestPyTupleEmpty() + { + var t = new PyTuple(); + Assert.AreEqual(0, t.Length()); + } + + [Test] + public void TestPyTupleBadCtor() + { + var i = new PyInt(5); + PyTuple t = null; + + var ex = Assert.Throws(() => t = new PyTuple(i)); + + Assert.AreEqual("object is not a tuple", ex.Message); + Assert.IsNull(t); + } + + [Test] + public void TestPyTupleCtorEmptyArray() + { + var a = new PyObject[] { }; + var t = new PyTuple(a); + + Assert.AreEqual(0, t.Length()); + } + + [Test] + public void TestPyTupleCtorArrayPyIntEmpty() + { + var a = new PyInt[] { }; + var t = new PyTuple(a); + + Assert.AreEqual(0, t.Length()); + } + + [Test] + public void TestPyTupleCtorArray() + { + var a = new PyObject[] { new PyInt(1), new PyString("Foo") }; + var t = new PyTuple(a); + + Assert.AreEqual(2, t.Length()); + } + + /// + /// Test PyTuple.Concat(...) doesn't let invalid appends happen + /// and throws and exception. + /// + /// + /// Test has second purpose. Currently it generated an Exception + /// that the GC failed to remove often and caused AppDomain unload + /// errors at the end of tests. See GH#397 for more info. + /// + /// Curious, on PY27 it gets a Unicode on the ex.Message. On PY3+ its string. + /// + [Test] + public void TestPyTupleInvalidAppend() + { + PyObject s = new PyString("foo"); + var t = new PyTuple(); + + var ex = Assert.Throws(() => t.Concat(s)); + + StringAssert.StartsWith("TypeError : can only concatenate tuple", ex.Message); + Assert.AreEqual(0, t.Length()); + Assert.IsEmpty(t); + } + + [Test] + public void TestPyTupleValidAppend() + { + var t0 = new PyTuple(); + var t = new PyTuple(); + t.Concat(t0); + + Assert.IsNotNull(t); + Assert.IsInstanceOf(typeof(PyTuple), t); + } + + [Test] + public void TestPyTupleStringConvert() + { + PyObject s = new PyString("foo"); + PyTuple t = PyTuple.AsTuple(s); + + Assert.IsNotNull(t); + Assert.IsInstanceOf(typeof(PyTuple), t); + Assert.AreEqual("f", t[0].ToString()); + Assert.AreEqual("o", t[1].ToString()); + Assert.AreEqual("o", t[2].ToString()); + } + + [Test] + public void TestPyTupleValidConvert() + { + var l = new PyList(); + PyTuple t = PyTuple.AsTuple(l); + + Assert.IsNotNull(t); + Assert.IsInstanceOf(typeof(PyTuple), t); + } + + [Test] + public void TestNewPyTupleFromPyTuple() + { + var t0 = new PyTuple(); + var t = new PyTuple(t0); + + Assert.IsNotNull(t); + Assert.IsInstanceOf(typeof(PyTuple), t); + } + + /// + /// TODO: Should this throw ArgumentError instead? + /// + [Test] + public void TestInvalidAsTuple() + { + var i = new PyInt(5); + PyTuple t = null; + + var ex = Assert.Throws(() => t = PyTuple.AsTuple(i)); + + Assert.AreEqual("TypeError : 'int' object is not iterable", ex.Message); + Assert.IsNull(t); + } + } +} diff --git a/src/embed_tests/TestPyWith.cs b/src/embed_tests/TestPyWith.cs new file mode 100644 index 000000000..fd3f8e662 --- /dev/null +++ b/src/embed_tests/TestPyWith.cs @@ -0,0 +1,88 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestPyWith + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + /// + /// Test that exception is raised in context manager that ignores it. + /// + [Test] + public void TestWithPositive() + { + var locals = new PyDict(); + + PythonEngine.Exec(@" +class CmTest: + def __enter__(self): + print('Enter') + return self + def __exit__(self, t, v, tb): + # Exception not handled, return will be False + print('Exit') + def fail(self): + return 5 / 0 + +a = CmTest() +", null, locals.Handle); + + var a = locals.GetItem("a"); + + try + { + Py.With(a, cmTest => + { + cmTest.fail(); + }); + } + catch (PythonException e) + { + Assert.IsTrue(e.Message.Contains("ZeroDivisionError")); + } + } + + + /// + /// Test that exception is not raised in context manager that handles it + /// + [Test] + public void TestWithNegative() + { + var locals = new PyDict(); + + PythonEngine.Exec(@" +class CmTest: + def __enter__(self): + print('Enter') + return self + def __exit__(self, t, v, tb): + # Signal exception is handled by returning true + return True + def fail(self): + return 5 / 0 + +a = CmTest() +", null, locals.Handle); + + var a = locals.GetItem("a"); + Py.With(a, cmTest => + { + cmTest.fail(); + }); + } + } +} diff --git a/src/embed_tests/TestPythonEngineProperties.cs b/src/embed_tests/TestPythonEngineProperties.cs new file mode 100644 index 000000000..01c6ae7e3 --- /dev/null +++ b/src/embed_tests/TestPythonEngineProperties.cs @@ -0,0 +1,187 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestPythonEngineProperties + { + [Test] + public static void GetBuildinfoDoesntCrash() + { + using (Py.GIL()) + { + string s = PythonEngine.BuildInfo; + + Assert.True(s.Length > 5); + Assert.True(s.Contains(",")); + } + } + + [Test] + public static void GetCompilerDoesntCrash() + { + using (Py.GIL()) + { + string s = PythonEngine.Compiler; + + Assert.True(s.Length > 0); + Assert.True(s.Contains("[")); + Assert.True(s.Contains("]")); + } + } + + [Test] + public static void GetCopyrightDoesntCrash() + { + using (Py.GIL()) + { + string s = PythonEngine.Copyright; + + Assert.True(s.Length > 0); + Assert.True(s.Contains("Python Software Foundation")); + } + } + + [Test] + public static void GetPlatformDoesntCrash() + { + using (Py.GIL()) + { + string s = PythonEngine.Platform; + + Assert.True(s.Length > 0); + Assert.True(s.Contains("x") || s.Contains("win")); + } + } + + [Test] + public static void GetVersionDoesntCrash() + { + using (Py.GIL()) + { + string s = PythonEngine.Version; + + Assert.True(s.Length > 0); + Assert.True(s.Contains(",")); + } + } + + [Test] + public static void GetPythonPathDefault() + { + PythonEngine.Initialize(); + string s = PythonEngine.PythonPath; + + StringAssert.Contains("python", s.ToLower()); + PythonEngine.Shutdown(); + } + + [Test] + public static void GetProgramNameDefault() + { + PythonEngine.Initialize(); + string s = PythonEngine.PythonHome; + + Assert.NotNull(s); + PythonEngine.Shutdown(); + } + + /// + /// Test default behavior of PYTHONHOME. If ENVVAR is set it will + /// return the same value. If not, returns EmptyString. + /// + /// + /// AppVeyor.yml has been update to tests with ENVVAR set. + /// + [Test] + public static void GetPythonHomeDefault() + { + string envPythonHome = Environment.GetEnvironmentVariable("PYTHONHOME") ?? ""; + + PythonEngine.Initialize(); + string enginePythonHome = PythonEngine.PythonHome; + + Assert.AreEqual(envPythonHome, enginePythonHome); + PythonEngine.Shutdown(); + } + + [Test] + public void SetPythonHome() + { + var pythonHome = "/dummypath/"; + + PythonEngine.PythonHome = pythonHome; + PythonEngine.Initialize(); + + Assert.AreEqual(pythonHome, PythonEngine.PythonHome); + PythonEngine.Shutdown(); + } + + [Test] + public void SetPythonHomeTwice() + { + var pythonHome = "/dummypath/"; + + PythonEngine.PythonHome = "/dummypath2/"; + PythonEngine.PythonHome = pythonHome; + PythonEngine.Initialize(); + + Assert.AreEqual(pythonHome, PythonEngine.PythonHome); + PythonEngine.Shutdown(); + } + + [Test] + public void SetProgramName() + { + var programName = "FooBar"; + + PythonEngine.ProgramName = programName; + PythonEngine.Initialize(); + + Assert.AreEqual(programName, PythonEngine.ProgramName); + PythonEngine.Shutdown(); + } + + [Test] + public void SetPythonPath() + { + if (Runtime.Runtime.pyversion == "2.7") + { + // Assert.Skip outputs as a warning (ie. pending to fix) + Assert.Pass(); + } + + PythonEngine.Initialize(); + string path = PythonEngine.PythonPath; + PythonEngine.Shutdown(); + + PythonEngine.ProgramName = path; + PythonEngine.Initialize(); + + Assert.AreEqual(path, PythonEngine.PythonPath); + PythonEngine.Shutdown(); + } + + [Test] + public void SetPythonPathExceptionOn27() + { + if (Runtime.Runtime.pyversion != "2.7") + { + Assert.Pass(); + } + + // Get previous path to avoid crashing Python + PythonEngine.Initialize(); + string path = PythonEngine.PythonPath; + PythonEngine.Shutdown(); + + var ex = Assert.Throws(() => PythonEngine.PythonPath = "foo"); + Assert.AreEqual("Set PythonPath not supported on Python 2", ex.Message); + + PythonEngine.Initialize(); + Assert.AreEqual(path, PythonEngine.PythonPath); + PythonEngine.Shutdown(); + } + } +} diff --git a/src/embed_tests/TestPythonException.cs b/src/embed_tests/TestPythonException.cs new file mode 100644 index 000000000..57a8d54af --- /dev/null +++ b/src/embed_tests/TestPythonException.cs @@ -0,0 +1,58 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestPythonException + { + private IntPtr _gs; + + [SetUp] + public void SetUp() + { + PythonEngine.Initialize(); + _gs = PythonEngine.AcquireLock(); + } + + [TearDown] + public void Dispose() + { + PythonEngine.ReleaseLock(_gs); + PythonEngine.Shutdown(); + } + + [Test] + public void TestMessage() + { + var list = new PyList(); + PyObject foo = null; + + var ex = Assert.Throws(() => foo = list[0]); + + Assert.AreEqual("IndexError : list index out of range", ex.Message); + Assert.IsNull(foo); + } + + [Test] + public void TestNoError() + { + var e = new PythonException(); // There is no PyErr to fetch + Assert.AreEqual("", e.Message); + } + + [Test] + public void TestPythonErrorTypeName() + { + try + { + var module = PythonEngine.ImportModule("really____unknown___module"); + Assert.Fail("Unknown module should not be loaded"); + } + catch (PythonException ex) + { + Assert.That(ex.PythonTypeName, Is.EqualTo("ModuleNotFoundError").Or.EqualTo("ImportError")); + } + } + } +} diff --git a/src/embed_tests/TestRuntime.cs b/src/embed_tests/TestRuntime.cs new file mode 100644 index 000000000..2e0598da7 --- /dev/null +++ b/src/embed_tests/TestRuntime.cs @@ -0,0 +1,92 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class TestRuntime + { + [Test] + public static void Py_IsInitializedValue() + { + Runtime.Runtime.Py_Finalize(); // In case another test left it on. + Assert.AreEqual(0, Runtime.Runtime.Py_IsInitialized()); + Runtime.Runtime.Py_Initialize(); + Assert.AreEqual(1, Runtime.Runtime.Py_IsInitialized()); + Runtime.Runtime.Py_Finalize(); + Assert.AreEqual(0, Runtime.Runtime.Py_IsInitialized()); + } + + [Test] + public static void RefCountTest() + { + Runtime.Runtime.Py_Initialize(); + IntPtr op = Runtime.Runtime.PyUnicode_FromString("FooBar"); + + // New object RefCount should be one + Assert.AreEqual(1, Runtime.Runtime.Refcount(op)); + + // Checking refcount didn't change refcount + Assert.AreEqual(1, Runtime.Runtime.Refcount(op)); + + // New reference doesn't increase refcount + IntPtr p = op; + Assert.AreEqual(1, Runtime.Runtime.Refcount(p)); + + // Py_IncRef/Py_DecRef increase and decrease RefCount + Runtime.Runtime.Py_IncRef(op); + Assert.AreEqual(2, Runtime.Runtime.Refcount(op)); + Runtime.Runtime.Py_DecRef(op); + Assert.AreEqual(1, Runtime.Runtime.Refcount(op)); + + // XIncref/XDecref increase and decrease RefCount + Runtime.Runtime.XIncref(op); + Assert.AreEqual(2, Runtime.Runtime.Refcount(op)); + Runtime.Runtime.XDecref(op); + Assert.AreEqual(1, Runtime.Runtime.Refcount(op)); + + Runtime.Runtime.Py_Finalize(); + } + + [Test] + public static void PyCheck_Iter_PyObject_IsIterable_Test() + { + Runtime.Runtime.Py_Initialize(); + + // Tests that a python list is an iterable, but not an iterator + var pyList = Runtime.Runtime.PyList_New(0); + Assert.IsFalse(Runtime.Runtime.PyIter_Check(pyList)); + Assert.IsTrue(Runtime.Runtime.PyObject_IsIterable(pyList)); + + // Tests that a python list iterator is both an iterable and an iterator + var pyListIter = Runtime.Runtime.PyObject_GetIter(pyList); + Assert.IsTrue(Runtime.Runtime.PyObject_IsIterable(pyListIter)); + Assert.IsTrue(Runtime.Runtime.PyIter_Check(pyListIter)); + + // Tests that a python float is neither an iterable nor an iterator + var pyFloat = Runtime.Runtime.PyFloat_FromDouble(2.73); + Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(pyFloat)); + Assert.IsFalse(Runtime.Runtime.PyIter_Check(pyFloat)); + + Runtime.Runtime.Py_Finalize(); + } + + [Test] + public static void PyCheck_Iter_PyObject_IsIterable_ThreadingLock_Test() + { + Runtime.Runtime.Py_Initialize(); + + // Create an instance of threading.Lock, which is one of the very few types that does not have the + // TypeFlags.HaveIter set in Python 2. This tests a different code path in PyObject_IsIterable and PyIter_Check. + var threading = Runtime.Runtime.PyImport_ImportModule("threading"); + var threadingDict = Runtime.Runtime.PyModule_GetDict(threading); + var lockType = Runtime.Runtime.PyDict_GetItemString(threadingDict, "Lock"); + var lockInstance = Runtime.Runtime.PyObject_CallObject(lockType, Runtime.Runtime.PyTuple_New(0)); + + Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(lockInstance)); + Assert.IsFalse(Runtime.Runtime.PyIter_Check(lockInstance)); + + Runtime.Runtime.Py_Finalize(); + } + } +} diff --git a/src/embed_tests/dynamic.cs b/src/embed_tests/dynamic.cs new file mode 100644 index 000000000..d75dc01d6 --- /dev/null +++ b/src/embed_tests/dynamic.cs @@ -0,0 +1,131 @@ +using System; +using System.Text; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class DynamicTest + { + private Py.GILState _gs; + + [SetUp] + public void SetUp() + { + _gs = Py.GIL(); + } + + [TearDown] + public void Dispose() + { + _gs.Dispose(); + } + + /// + /// Set the attribute of a PyObject with a .NET object. + /// + [Test] + public void AssignObject() + { + var stream = new StringBuilder(); + dynamic sys = Py.Import("sys"); + sys.testattr = stream; + // Check whether there are the same object. + dynamic _stream = sys.testattr.AsManagedObject(typeof(StringBuilder)); + Assert.AreEqual(_stream, stream); + + PythonEngine.RunSimpleString( + "import sys\n" + + "sys.testattr.Append('Hello!')\n"); + Assert.AreEqual(stream.ToString(), "Hello!"); + } + + /// + /// Set the attribute of a PyObject to null. + /// + [Test] + public void AssignNone() + { + dynamic sys = Py.Import("sys"); + sys.testattr = new StringBuilder(); + Assert.IsNotNull(sys.testattr); + + sys.testattr = null; + Assert.IsNull(sys.testattr); + } + + /// + /// Check whether we can get the attr of a python object when the + /// value of attr is a PyObject. + /// + /// + /// FIXME: Issue on Travis PY27: Error : Python.EmbeddingTest.dynamicTest.AssignPyObject + /// Python.Runtime.PythonException : ImportError : /home/travis/virtualenv/python2.7.9/lib/python2.7/lib-dynload/_io.so: undefined symbol: _PyLong_AsInt + /// + [Test] + public void AssignPyObject() + { + if (Environment.GetEnvironmentVariable("TRAVIS") == "true" && + Environment.GetEnvironmentVariable("TRAVIS_PYTHON_VERSION") == "2.7") + { + Assert.Ignore("Fails on Travis/PY27: ImportError: ... undefined symbol: _PyLong_AsInt"); + } + + dynamic sys = Py.Import("sys"); + dynamic io = Py.Import("io"); + sys.testattr = io.StringIO(); + dynamic bb = sys.testattr; // Get the PyObject + bb.write("Hello!"); + Assert.AreEqual(bb.getvalue().ToString(), "Hello!"); + } + + /// + /// Pass the .NET object in Python side. + /// + [Test] + public void PassObjectInPython() + { + var stream = new StringBuilder(); + dynamic sys = Py.Import("sys"); + sys.testattr1 = stream; + + // Pass the .NET object in Python side + PythonEngine.RunSimpleString( + "import sys\n" + + "sys.testattr2 = sys.testattr1\n" + ); + + // Compare in Python + PythonEngine.RunSimpleString( + "import sys\n" + + "sys.testattr3 = sys.testattr1 is sys.testattr2\n" + ); + Assert.AreEqual(sys.testattr3.ToString(), "True"); + + // Compare in .NET + Assert.IsTrue(sys.testattr1.Equals(sys.testattr2)); + } + + /// + /// Pass the PyObject in .NET side + /// + [Test] + public void PassPyObjectInNet() + { + var stream = new StringBuilder(); + dynamic sys = Py.Import("sys"); + sys.testattr1 = stream; + sys.testattr2 = sys.testattr1; + + // Compare in Python + PyObject res = PythonEngine.RunString( + "import sys\n" + + "sys.testattr3 = sys.testattr1 is sys.testattr2\n" + ); + Assert.AreEqual(sys.testattr3.ToString(), "True"); + + // Compare in .NET + Assert.IsTrue(sys.testattr1.Equals(sys.testattr2)); + } + } +} diff --git a/src/embed_tests/fixtures/PyImportTest/__init__.py b/src/embed_tests/fixtures/PyImportTest/__init__.py new file mode 100644 index 000000000..40a96afc6 --- /dev/null +++ b/src/embed_tests/fixtures/PyImportTest/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/src/embed_tests/fixtures/PyImportTest/cast_global_var.py b/src/embed_tests/fixtures/PyImportTest/cast_global_var.py new file mode 100644 index 000000000..f9499539e --- /dev/null +++ b/src/embed_tests/fixtures/PyImportTest/cast_global_var.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- + +FOO = 1 + + +def test_foo(): + return FOO diff --git a/src/embed_tests/fixtures/PyImportTest/sysargv.py b/src/embed_tests/fixtures/PyImportTest/sysargv.py new file mode 100644 index 000000000..2e1508bff --- /dev/null +++ b/src/embed_tests/fixtures/PyImportTest/sysargv.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +import sys +# if argv is available, as expected, then no exception +num_args = len(sys.argv) diff --git a/src/embed_tests/fixtures/PyImportTest/test/__init__.py b/src/embed_tests/fixtures/PyImportTest/test/__init__.py new file mode 100644 index 000000000..40a96afc6 --- /dev/null +++ b/src/embed_tests/fixtures/PyImportTest/test/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/src/embed_tests/fixtures/PyImportTest/test/one.py b/src/embed_tests/fixtures/PyImportTest/test/one.py new file mode 100644 index 000000000..40a96afc6 --- /dev/null +++ b/src/embed_tests/fixtures/PyImportTest/test/one.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/src/embed_tests/packages.config b/src/embed_tests/packages.config index fdc687a35..8c175f441 100644 --- a/src/embed_tests/packages.config +++ b/src/embed_tests/packages.config @@ -1,5 +1,5 @@ - - + + diff --git a/src/embed_tests/pyimport.cs b/src/embed_tests/pyimport.cs index 58da0ac13..acb3433de 100644 --- a/src/embed_tests/pyimport.cs +++ b/src/embed_tests/pyimport.cs @@ -1,76 +1,87 @@ using System; -using System.Reflection; -using System.Collections.Generic; +using System.IO; using NUnit.Framework; using Python.Runtime; namespace Python.EmbeddingTest { - [TestFixture] + /// + /// Test Import unittests and regressions + /// + /// + /// Keeping in old-style SetUp/TearDown due to required SetUp. + /// The required directory structure was added to .\pythonnet\src\embed_tests\fixtures\ directory: + /// + PyImportTest/ + /// | - __init__.py + /// | + test/ + /// | | - __init__.py + /// | | - one.py + /// public class PyImportTest { - private IntPtr gs; + private IntPtr _gs; [SetUp] public void SetUp() { PythonEngine.Initialize(); - gs = PythonEngine.AcquireLock(); + _gs = PythonEngine.AcquireLock(); - //string here = Environment.CurrentDirectory; - //trunk\pythonnet\src\embed_tests\bin\x86\DebugWin + /* Append the tests directory to sys.path + * using reflection to circumvent the private + * modifiers placed on most Runtime methods. */ +#if NETCOREAPP + const string s = "../../fixtures"; +#else + const string s = "../fixtures"; +#endif + string testPath = Path.Combine(TestContext.CurrentContext.TestDirectory, s); - /* - * Append the tests directory to sys.path - * using reflection to circumvent the private modifires placed on most Runtime methods. - */ - const string s = @"../../../../tests"; - - Type RTClass = typeof(Runtime.Runtime); - - /* pyStrPtr = PyString_FromString(s); */ - MethodInfo PyString_FromString = RTClass.GetMethod("PyString_FromString", - BindingFlags.NonPublic | BindingFlags.Static); - object[] funcArgs = new object[1]; - funcArgs[0] = s; - IntPtr pyStrPtr = (IntPtr)PyString_FromString.Invoke(null, funcArgs); - - /* SysDotPath = sys.path */ - MethodInfo PySys_GetObject = RTClass.GetMethod("PySys_GetObject", - BindingFlags.NonPublic | BindingFlags.Static); - funcArgs[0] = "path"; - IntPtr SysDotPath = (IntPtr)PySys_GetObject.Invoke(null, funcArgs); - - /* SysDotPath.append(*pyStrPtr) */ - MethodInfo PyList_Append = RTClass.GetMethod("PyList_Append", BindingFlags.NonPublic | BindingFlags.Static); - funcArgs = new object[] { SysDotPath, pyStrPtr }; - int r = (int)PyList_Append.Invoke(null, funcArgs); + IntPtr str = Runtime.Runtime.PyString_FromString(testPath); + IntPtr path = Runtime.Runtime.PySys_GetObject("path"); + Runtime.Runtime.PyList_Append(path, str); } [TearDown] - public void TearDown() + public void Dispose() { - PythonEngine.ReleaseLock(gs); + PythonEngine.ReleaseLock(_gs); PythonEngine.Shutdown(); } /// /// Test subdirectory import /// - /// - /// The required directory structure was added to the \trunk\pythonnet\src\tests directory: - /// - /// PyImportTest/ - /// __init__.py - /// test/ - /// __init__.py - /// one.py - /// [Test] public void TestDottedName() { PyObject module = PythonEngine.ImportModule("PyImportTest.test.one"); - Assert.IsNotNull(module, ">>> import PyImportTest.test.one # FAILED"); + Assert.IsNotNull(module); + } + + /// + /// Tests that sys.args is set. If it wasn't exception would be raised. + /// + [Test] + public void TestSysArgsImportException() + { + PyObject module = PythonEngine.ImportModule("PyImportTest.sysargv"); + Assert.IsNotNull(module); + } + + /// + /// Test Global Variable casting. GH#420 + /// + [Test] + public void TestCastGlobalVar() + { + dynamic foo = Py.Import("PyImportTest.cast_global_var"); + Assert.AreEqual("1", foo.FOO.ToString()); + Assert.AreEqual("1", foo.test_foo().ToString()); + + foo.FOO = 2; + Assert.AreEqual("2", foo.FOO.ToString()); + Assert.AreEqual("2", foo.test_foo().ToString()); } } } diff --git a/src/embed_tests/pyinitialize.cs b/src/embed_tests/pyinitialize.cs new file mode 100644 index 000000000..2f9aae2c7 --- /dev/null +++ b/src/embed_tests/pyinitialize.cs @@ -0,0 +1,78 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class PyInitializeTest + { + /// + /// Tests issue with multiple simple Initialize/Shutdowns. + /// Fixed by #343 + /// + [Test] + public static void StartAndStopTwice() + { + PythonEngine.Initialize(); + PythonEngine.Shutdown(); + + PythonEngine.Initialize(); + PythonEngine.Shutdown(); + } + + [Test] + public static void LoadDefaultArgs() + { + using (new PythonEngine()) + using (var argv = new PyList(Runtime.Runtime.PySys_GetObject("argv"))) + { + Assert.AreNotEqual(0, argv.Length()); + } + } + + [Test] + public static void LoadSpecificArgs() + { + var args = new[] { "test1", "test2" }; + using (new PythonEngine(args)) + using (var argv = new PyList(Runtime.Runtime.PySys_GetObject("argv"))) + { + Assert.AreEqual(args[0], argv[0].ToString()); + Assert.AreEqual(args[1], argv[1].ToString()); + } + } + + /// + /// Failing test demonstrating current issue with OverflowException (#376) + /// and ArgumentException issue after that one is fixed. + /// More complex version of StartAndStopTwice test + /// + [Test] + [Ignore("GH#376: System.OverflowException : Arithmetic operation resulted in an overflow")] + //[Ignore("System.ArgumentException : Cannot pass a GCHandle across AppDomains")] + public void ReInitialize() + { + var code = "from System import Int32\n"; + PythonEngine.Initialize(); + using (Py.GIL()) + { + // Import any class or struct from .NET + PythonEngine.RunSimpleString(code); + } + PythonEngine.Shutdown(); + + PythonEngine.Initialize(); + using (Py.GIL()) + { + // Import a class/struct from .NET + // This class/struct must be imported during the first initialization. + PythonEngine.RunSimpleString(code); + // Create an instance of the class/struct + // System.OverflowException Exception will be raised here. + // If replacing int with Int64, OverflowException will be replaced with AppDomain exception. + PythonEngine.RunSimpleString("Int32(1)"); + } + PythonEngine.Shutdown(); + } + } +} diff --git a/src/embed_tests/pyiter.cs b/src/embed_tests/pyiter.cs deleted file mode 100644 index 4939e22fe..000000000 --- a/src/embed_tests/pyiter.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using NUnit.Framework; -using Python.Runtime; - -namespace Python.EmbeddingTest -{ - [TestFixture] - public class PyIterTest - { - private IntPtr gs; - - [SetUp] - public void SetUp() - { - PythonEngine.Initialize(); - gs = PythonEngine.AcquireLock(); - } - - [TearDown] - public void TearDown() - { - PythonEngine.ReleaseLock(gs); - PythonEngine.Shutdown(); - } - - [Test] - public void TestOnPyList() - { - PyList list = new PyList(); - list.Append(new PyString("foo")); - list.Append(new PyString("bar")); - list.Append(new PyString("baz")); - List result = new List(); - foreach (PyObject item in list) - result.Add(item.ToString()); - Assert.AreEqual(3, result.Count); - Assert.AreEqual("foo", result[0]); - Assert.AreEqual("bar", result[1]); - Assert.AreEqual("baz", result[2]); - } - } -} \ No newline at end of file diff --git a/src/embed_tests/pylong.cs b/src/embed_tests/pylong.cs deleted file mode 100644 index 1b5ffdb66..000000000 --- a/src/embed_tests/pylong.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using NUnit.Framework; -using Python.Runtime; - -namespace Python.EmbeddingTest -{ - [TestFixture] - public class PyLongTest - { - private IntPtr gs; - - [SetUp] - public void SetUp() - { - PythonEngine.Initialize(); - gs = PythonEngine.AcquireLock(); - } - - [TearDown] - public void TearDown() - { - PythonEngine.ReleaseLock(gs); - PythonEngine.Shutdown(); - } - - [Test] - public void TestToInt64() - { - long largeNumber = 8L * 1024L * 1024L * 1024L; // 8 GB - PyLong pyLargeNumber = new PyLong(largeNumber); - Assert.AreEqual(largeNumber, pyLargeNumber.ToInt64()); - } - } -} diff --git a/src/embed_tests/pyobject.cs b/src/embed_tests/pyobject.cs deleted file mode 100644 index ba267c3a5..000000000 --- a/src/embed_tests/pyobject.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using NUnit.Framework; -using Python.Runtime; - -namespace Python.EmbeddingTest -{ - [TestFixture] - public class PyObjectTest - { - private IntPtr gs; - - [SetUp] - public void SetUp() - { - PythonEngine.Initialize(); - gs = PythonEngine.AcquireLock(); - } - - [TearDown] - public void TearDown() - { - PythonEngine.ReleaseLock(gs); - PythonEngine.Shutdown(); - } - - [Test] - public void TestUnicode() - { - PyObject s = new PyString("foo\u00e9"); - Assert.AreEqual("foo\u00e9", s.ToString()); - } - } -} \ No newline at end of file diff --git a/src/embed_tests/pyrunstring.cs b/src/embed_tests/pyrunstring.cs new file mode 100644 index 000000000..07875a2a8 --- /dev/null +++ b/src/embed_tests/pyrunstring.cs @@ -0,0 +1,76 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + public class RunStringTest + { + private Py.GILState _gs; + + [SetUp] + public void SetUp() + { + _gs = Py.GIL(); + } + + [TearDown] + public void Dispose() + { + _gs.Dispose(); + } + + [Test] + public void TestRunSimpleString() + { + int aa = PythonEngine.RunSimpleString("import sys"); + Assert.AreEqual(0, aa); + + int bb = PythonEngine.RunSimpleString("import 1234"); + Assert.AreEqual(-1, bb); + } + + [Test] + public void TestEval() + { + dynamic sys = Py.Import("sys"); + sys.attr1 = 100; + var locals = new PyDict(); + locals.SetItem("sys", sys); + locals.SetItem("a", new PyInt(10)); + + object b = PythonEngine.Eval("sys.attr1 + a + 1", null, locals.Handle) + .AsManagedObject(typeof(int)); + Assert.AreEqual(111, b); + } + + [Test] + public void TestExec() + { + dynamic sys = Py.Import("sys"); + sys.attr1 = 100; + var locals = new PyDict(); + locals.SetItem("sys", sys); + locals.SetItem("a", new PyInt(10)); + + PythonEngine.Exec("c = sys.attr1 + a + 1", null, locals.Handle); + object c = locals.GetItem("c").AsManagedObject(typeof(int)); + Assert.AreEqual(111, c); + } + + [Test] + public void TestExec2() + { + string code = @" +class Test1(): + pass + +class Test2(): + def __init__(self): + Test1() + +Test2()"; + PythonEngine.Exec(code); + } + } +} diff --git a/src/embed_tests/pythonexception.cs b/src/embed_tests/pythonexception.cs deleted file mode 100644 index 359040601..000000000 --- a/src/embed_tests/pythonexception.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using NUnit.Framework; -using Python.Runtime; - -namespace Python.EmbeddingTest -{ - [TestFixture] - public class PythonExceptionTest - { - private IntPtr gs; - - [SetUp] - public void SetUp() - { - PythonEngine.Initialize(); - gs = PythonEngine.AcquireLock(); - } - - [TearDown] - public void TearDown() - { - PythonEngine.ReleaseLock(gs); - PythonEngine.Shutdown(); - } - - [Test] - public void TestMessage() - { - PyList list = new PyList(); - try - { - PyObject junk = list[0]; - } - catch (PythonException e) - { - Assert.AreEqual("IndexError : list index out of range", e.Message); - } - } - - [Test] - public void TestNoError() - { - PythonException e = new PythonException(); //There is no PyErr to fetch - Assert.AreEqual("", e.Message); - } - } -} \ No newline at end of file diff --git a/src/monoclr/pynetinit.c b/src/monoclr/pynetinit.c index ed09d45d7..8b49ddae3 100644 --- a/src/monoclr/pynetinit.c +++ b/src/monoclr/pynetinit.c @@ -135,7 +135,7 @@ void main_thread_handler(gpointer user_data) int ii = 0; for (ii = 0; ii < PyList_Size(syspath); ++ii) { -#if PY_MAJOR_VERSION > 2 +#if PY_MAJOR_VERSION >= 3 Py_ssize_t wlen; wchar_t *wstr = PyUnicode_AsWideCharString(PyList_GetItem(syspath, ii), &wlen); char *pydir = (char*)malloc(wlen + 1); @@ -150,7 +150,7 @@ void main_thread_handler(gpointer user_data) strncpy(curdir, strlen(pydir) > 0 ? pydir : ".", 1024); strncat(curdir, slash, 1024); -#if PY_MAJOR_VERSION > 2 +#if PY_MAJOR_VERSION >= 3 free(pydir); #endif diff --git a/pythonnet.snk b/src/pythonnet.snk similarity index 100% rename from pythonnet.snk rename to src/pythonnet.snk diff --git a/src/runtime/CustomMarshaler.cs b/src/runtime/CustomMarshaler.cs new file mode 100644 index 000000000..b51911816 --- /dev/null +++ b/src/runtime/CustomMarshaler.cs @@ -0,0 +1,240 @@ +using System; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace Python.Runtime +{ + /// + /// Abstract class defining boiler plate methods that + /// Custom Marshalers will use. + /// + internal abstract class MarshalerBase : ICustomMarshaler + { + public object MarshalNativeToManaged(IntPtr pNativeData) + { + throw new NotImplementedException(); + } + + public abstract IntPtr MarshalManagedToNative(object managedObj); + + public void CleanUpNativeData(IntPtr pNativeData) + { + Marshal.FreeHGlobal(pNativeData); + } + + public void CleanUpManagedData(object managedObj) + { + // Let GC deal with it + } + + public int GetNativeDataSize() + { + return IntPtr.Size; + } + } + + + /// + /// Custom Marshaler to deal with Managed String to Native + /// conversion differences on UCS2/UCS4. + /// + internal class UcsMarshaler : MarshalerBase + { + private static readonly MarshalerBase Instance = new UcsMarshaler(); + private static readonly Encoding PyEncoding = Runtime.PyEncoding; + + public override IntPtr MarshalManagedToNative(object managedObj) + { + var s = managedObj as string; + + if (s == null) + { + return IntPtr.Zero; + } + + byte[] bStr = PyEncoding.GetBytes(s + "\0"); + IntPtr mem = Marshal.AllocHGlobal(bStr.Length); + try + { + Marshal.Copy(bStr, 0, mem, bStr.Length); + } + catch (Exception) + { + Marshal.FreeHGlobal(mem); + throw; + } + + return mem; + } + + public static ICustomMarshaler GetInstance(string cookie) + { + return Instance; + } + + public static string PtrToStringUni(IntPtr p) + { + if (p == IntPtr.Zero) + { + return null; + } + + int size = GetUnicodeByteLength(p); + var buffer = new byte[size]; + Marshal.Copy(p, buffer, 0, size); + return PyEncoding.GetString(buffer, 0, size); + } + + public static int GetUnicodeByteLength(IntPtr p) + { + var len = 0; + while (true) + { + int c = Runtime._UCS == 2 + ? Marshal.ReadInt16(p, len * 2) + : Marshal.ReadInt32(p, len * 4); + + if (c == 0) + { + return len * Runtime._UCS; + } + checked + { + ++len; + } + } + } + + /// + /// Utility function for Marshaling Unicode on PY3 and AnsiStr on PY2. + /// Use on functions whose Input signatures changed between PY2/PY3. + /// Ex. Py_SetPythonHome + /// + /// Managed String + /// + /// Ptr to Native String ANSI(PY2)/Unicode(PY3/UCS2)/UTF32(PY3/UCS4. + /// + /// + /// You MUST deallocate the IntPtr of the Return when done with it. + /// + public static IntPtr Py3UnicodePy2StringtoPtr(string s) + { + return Runtime.IsPython3 + ? Instance.MarshalManagedToNative(s) + : Marshal.StringToHGlobalAnsi(s); + } + + /// + /// Utility function for Marshaling Unicode IntPtr on PY3 and + /// AnsiStr IntPtr on PY2 to Managed Strings. Use on Python functions + /// whose return type changed between PY2/PY3. + /// Ex. Py_GetPythonHome + /// + /// Native Ansi/Unicode/UTF32 String + /// + /// Managed String + /// + public static string PtrToPy3UnicodePy2String(IntPtr p) + { + return Runtime.IsPython3 + ? PtrToStringUni(p) + : Marshal.PtrToStringAnsi(p); + } + } + + + /// + /// Custom Marshaler to deal with Managed String Arrays to Native + /// conversion differences on UCS2/UCS4. + /// + internal class StrArrayMarshaler : MarshalerBase + { + private static readonly MarshalerBase Instance = new StrArrayMarshaler(); + private static readonly Encoding PyEncoding = Runtime.PyEncoding; + + public override IntPtr MarshalManagedToNative(object managedObj) + { + var argv = managedObj as string[]; + + if (argv == null) + { + return IntPtr.Zero; + } + + int totalStrLength = argv.Sum(arg => arg.Length + 1); + int memSize = argv.Length * IntPtr.Size + totalStrLength * Runtime._UCS; + + IntPtr mem = Marshal.AllocHGlobal(memSize); + try + { + // Preparing array of pointers to strings + IntPtr curStrPtr = mem + argv.Length * IntPtr.Size; + for (var i = 0; i < argv.Length; i++) + { + byte[] bStr = PyEncoding.GetBytes(argv[i] + "\0"); + Marshal.Copy(bStr, 0, curStrPtr, bStr.Length); + Marshal.WriteIntPtr(mem + i * IntPtr.Size, curStrPtr); + curStrPtr += bStr.Length; + } + } + catch (Exception) + { + Marshal.FreeHGlobal(mem); + throw; + } + + return mem; + } + + public static ICustomMarshaler GetInstance(string cookie) + { + return Instance; + } + } + + + /// + /// Custom Marshaler to deal with Managed String to Native + /// conversion on UTF-8. Use on functions that expect UTF-8 encoded + /// strings like `PyUnicode_FromStringAndSize` + /// + /// + /// If instead we used `MarshalAs(UnmanagedType.LPWStr)` the output to + /// `foo` would be `f\x00o\x00o\x00`. + /// + internal class Utf8Marshaler : MarshalerBase + { + private static readonly MarshalerBase Instance = new Utf8Marshaler(); + private static readonly Encoding PyEncoding = Encoding.UTF8; + + public override IntPtr MarshalManagedToNative(object managedObj) + { + var s = managedObj as string; + + if (s == null) + { + return IntPtr.Zero; + } + + byte[] bStr = PyEncoding.GetBytes(s + "\0"); + IntPtr mem = Marshal.AllocHGlobal(bStr.Length); + try + { + Marshal.Copy(bStr, 0, mem, bStr.Length); + } + catch (Exception) + { + Marshal.FreeHGlobal(mem); + throw; + } + + return mem; + } + + public static ICustomMarshaler GetInstance(string cookie) + { + return Instance; + } + } +} diff --git a/src/runtime/Properties/AssemblyInfo.cs b/src/runtime/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..a5d33c7ab --- /dev/null +++ b/src/runtime/Properties/AssemblyInfo.cs @@ -0,0 +1,11 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Python for .NET")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyDefaultAlias("Python.Runtime.dll")] + +[assembly: InternalsVisibleTo("Python.EmbeddingTest")] diff --git a/src/runtime/Python.Runtime.15.csproj b/src/runtime/Python.Runtime.15.csproj new file mode 100644 index 000000000..cfde0a127 --- /dev/null +++ b/src/runtime/Python.Runtime.15.csproj @@ -0,0 +1,140 @@ + + + + net40;netstandard2.0 + AnyCPU + DebugMono;DebugMonoPY3;ReleaseMono;ReleaseMonoPY3;DebugWin;DebugWinPY3;ReleaseWin;ReleaseWinPY3 + net45 + Python.Runtime + Python.Runtime + Python.Runtime + 2.4.0 + false + false + false + false + false + false + bin\ + false + $(OutputPath)\$(AssemblyName).xml + $(OutputPath)\$(TargetFramework)\$(AssemblyName).xml + 1591;NU1701 + ..\..\ + $(SolutionDir)\bin\ + $(PythonBuildDir)\$(TargetFramework)\ + 6 + True + ..\pythonnet.snk + $(PYTHONNET_DEFINE_CONSTANTS) + XPLAT + $(DefineConstants);$(CustomDefineConstants);$(BaseDefineConstants); + $(DefineConstants);NETSTANDARD + $(DefineConstants);TRACE;DEBUG + $(NuGetPackageRoot)\microsoft.targetingpack.netframework.v4.5\1.0.1\lib\net45\ + $(PYTHONNET_PY2_VERSION) + PYTHON27 + $(PYTHONNET_PY3_VERSION) + PYTHON36 + $(PYTHONNET_WIN_DEFINE_CONSTANTS) + UCS2 + $(PYTHONNET_MONO_DEFINE_CONSTANTS) + UCS4;MONO_LINUX;PYTHON_WITH_PYMALLOC + $(PYTHONNET_INTEROP_FILE) + + + false + full + + + true + pdbonly + + + true + false + full + + + true + true + portable + + + + $(DefineConstants);PYTHON2;$(Python2Version);$(PythonMonoDefineConstants) + + + $(DefineConstants);PYTHON3;$(Python3Version);$(PythonMonoDefineConstants) + + + $(DefineConstants);PYTHON2;$(Python2Version);$(PythonMonoDefineConstants);TRACE;DEBUG + + + $(DefineConstants);PYTHON3;$(Python3Version);$(PythonMonoDefineConstants);TRACE;DEBUG + + + $(DefineConstants);PYTHON2;$(Python2Version);$(PythonWinDefineConstants) + + + $(DefineConstants);PYTHON3;$(Python3Version);$(PythonWinDefineConstants) + + + $(DefineConstants);PYTHON2;$(Python2Version);$(PythonWinDefineConstants);TRACE;DEBUG + + + $(DefineConstants);PYTHON3;$(Python3Version);$(PythonWinDefineConstants);TRACE;DEBUG + + + + + + + + + + + + + + + + + + + + + + clr.py + + + + + + + + + + + + + + + + + + + + $(TargetPath) + $(TargetDir)$(TargetName).pdb + + + + + + + + + + + diff --git a/src/runtime/Python.Runtime.csproj b/src/runtime/Python.Runtime.csproj index 81616448c..82825a626 100644 --- a/src/runtime/Python.Runtime.csproj +++ b/src/runtime/Python.Runtime.csproj @@ -1,122 +1,86 @@ - + Debug - x86 + AnyCPU {097B4AC0-74E9-4C58-BCF8-C69746EC8271} Library - false Python.Runtime Python.Runtime + bin\Python.Runtime.xml + bin\ + v4.0 + + 1591 ..\..\ - $(SolutionDir) - - - bin\x86\ReleaseMono\ - PYTHON2;PYTHON27;UCS4 + $(SolutionDir)\bin\ + Properties + 6 true - true - pdbonly + false + ..\pythonnet.snk + + + + + + PYTHON2;PYTHON27;UCS4 true pdbonly - x86 - false - true - - bin\x64\ReleaseWin\ - PYTHON2;PYTHON27;UCS2 - true + + PYTHON3;PYTHON36;UCS4 true pdbonly - x64 - false - true - + true - bin\x86\DebugMono\ - TRACE;DEBUG;PYTHON2;PYTHON27;UCS4 - true + PYTHON2;PYTHON27;UCS4;TRACE;DEBUG false full - x86 - false - false - false - + true - bin\x64\DebugMono\ - TRACE;DEBUG;PYTHON2;PYTHON27;UCS4 - true + PYTHON3;PYTHON36;UCS4;TRACE;DEBUG false full - x64 - + + PYTHON2;PYTHON27;UCS2 + true + pdbonly + + + PYTHON3;PYTHON36;UCS2 + true + pdbonly + + true - bin\x86\DebugWin\ - TRACE;DEBUG;PYTHON2;PYTHON27;UCS2 - true + PYTHON2;PYTHON27;UCS2;TRACE;DEBUG false full - x86 - false - false - false - + true - bin\x64\DebugWin\ - TRACE;DEBUG;PYTHON2;PYTHON27;UCS2 - true + PYTHON3;PYTHON36;UCS2;TRACE;DEBUG false full - x64 - - - - - False - ..\..\packages\MonoGAC\Mono.Posix\4.0.0.0__0738eb9f132ed756\Mono.Posix.dll - - - - - - - False - ..\..\packages\MonoGAC\Mono.Posix\4.0.0.0__0738eb9f132ed756\Mono.Posix.dll - - - - + + + Properties\SharedAssemblyInfo.cs + - @@ -127,6 +91,7 @@ + @@ -152,7 +117,6 @@ - @@ -165,6 +129,7 @@ + @@ -173,14 +138,13 @@ + - - @@ -188,8 +152,6 @@ - - @@ -197,15 +159,12 @@ - - - $(TargetPath) $(TargetDir)$(TargetName).pdb - + - + \ No newline at end of file diff --git a/src/runtime/Util.cs b/src/runtime/Util.cs new file mode 100644 index 000000000..dd4418cc9 --- /dev/null +++ b/src/runtime/Util.cs @@ -0,0 +1,33 @@ +using System; +using System.Runtime.InteropServices; + +namespace Python.Runtime +{ + internal class Util + { + internal static Int64 ReadCLong(IntPtr tp, int offset) + { + // On Windows, a C long is always 32 bits. + if (Runtime.IsWindows || Runtime.Is32Bit) + { + return Marshal.ReadInt32(tp, offset); + } + else + { + return Marshal.ReadInt64(tp, offset); + } + } + + internal static void WriteCLong(IntPtr type, int offset, Int64 flags) + { + if (Runtime.IsWindows || Runtime.Is32Bit) + { + Marshal.WriteInt32(type, offset, (Int32)(flags & 0xffffffffL)); + } + else + { + Marshal.WriteInt64(type, offset, flags); + } + } + } +} \ No newline at end of file diff --git a/src/runtime/arrayobject.cs b/src/runtime/arrayobject.cs index 2fe433e57..a10688749 100644 --- a/src/runtime/arrayobject.cs +++ b/src/runtime/arrayobject.cs @@ -1,6 +1,5 @@ using System; using System.Collections; -using System.Reflection; namespace Python.Runtime { @@ -22,13 +21,13 @@ internal override bool CanSubclass() public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { - ArrayObject self = GetManagedObject(tp) as ArrayObject; + var self = GetManagedObject(tp) as ArrayObject; if (Runtime.PyTuple_Size(args) != 1) { return Exceptions.RaiseTypeError("array expects 1 argument"); } IntPtr op = Runtime.PyTuple_GetItem(args, 0); - Object result; + object result; if (!Converter.ToManaged(op, self.type, out result, true)) { @@ -38,17 +37,16 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) } - //==================================================================== - // Implements __getitem__ for array types. - //==================================================================== - + /// + /// Implements __getitem__ for array types. + /// public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) { - CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob); - Array items = obj.inst as Array; + var obj = (CLRObject)GetManagedObject(ob); + var items = obj.inst as Array; Type itemType = obj.inst.GetType().GetElementType(); int rank = items.Rank; - int index = 0; + int index; object value; // Note that CLR 1.0 only supports int indexes - methods to @@ -62,7 +60,7 @@ public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) if (rank == 1) { - index = (int)Runtime.PyInt_AsLong(idx); + index = Runtime.PyInt_AsLong(idx); if (Exceptions.ErrorOccurred()) { @@ -80,33 +78,29 @@ public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) } catch (IndexOutOfRangeException) { - Exceptions.SetError(Exceptions.IndexError, - "array index out of range" - ); + Exceptions.SetError(Exceptions.IndexError, "array index out of range"); return IntPtr.Zero; } - return Converter.ToPython(items.GetValue(index), itemType); + return Converter.ToPython(value, itemType); } // Multi-dimensional arrays can be indexed a la: list[1, 2, 3]. if (!Runtime.PyTuple_Check(idx)) { - Exceptions.SetError(Exceptions.TypeError, - "invalid index value" - ); + Exceptions.SetError(Exceptions.TypeError, "invalid index value"); return IntPtr.Zero; } int count = Runtime.PyTuple_Size(idx); - Array args = Array.CreateInstance(typeof(Int32), count); + var args = new int[count]; - for (int i = 0; i < count; i++) + for (var i = 0; i < count; i++) { IntPtr op = Runtime.PyTuple_GetItem(idx, i); - index = (int)Runtime.PyInt_AsLong(op); + index = Runtime.PyInt_AsLong(op); if (Exceptions.ErrorOccurred()) { @@ -123,13 +117,11 @@ public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) try { - value = items.GetValue((int[])args); + value = items.GetValue(args); } catch (IndexOutOfRangeException) { - Exceptions.SetError(Exceptions.IndexError, - "array index out of range" - ); + Exceptions.SetError(Exceptions.IndexError, "array index out of range"); return IntPtr.Zero; } @@ -137,17 +129,16 @@ public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) } - //==================================================================== - // Implements __setitem__ for array types. - //==================================================================== - + /// + /// Implements __setitem__ for array types. + /// public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) { - CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob); - Array items = obj.inst as Array; + var obj = (CLRObject)GetManagedObject(ob); + var items = obj.inst as Array; Type itemType = obj.inst.GetType().GetElementType(); int rank = items.Rank; - int index = 0; + int index; object value; if (items.IsReadOnly) @@ -163,7 +154,7 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) if (rank == 1) { - index = (int)Runtime.PyInt_AsLong(idx); + index = Runtime.PyInt_AsLong(idx); if (Exceptions.ErrorOccurred()) { @@ -182,9 +173,7 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) } catch (IndexOutOfRangeException) { - Exceptions.SetError(Exceptions.IndexError, - "array index out of range" - ); + Exceptions.SetError(Exceptions.IndexError, "array index out of range"); return -1; } @@ -198,13 +187,12 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) } int count = Runtime.PyTuple_Size(idx); + var args = new int[count]; - Array args = Array.CreateInstance(typeof(Int32), count); - - for (int i = 0; i < count; i++) + for (var i = 0; i < count; i++) { IntPtr op = Runtime.PyTuple_GetItem(idx, i); - index = (int)Runtime.PyInt_AsLong(op); + index = Runtime.PyInt_AsLong(op); if (Exceptions.ErrorOccurred()) { @@ -222,13 +210,11 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) try { - items.SetValue(value, (int[])args); + items.SetValue(value, args); } catch (IndexOutOfRangeException) { - Exceptions.SetError(Exceptions.IndexError, - "array index out of range" - ); + Exceptions.SetError(Exceptions.IndexError, "array index out of range"); return -1; } @@ -236,15 +222,14 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) } - //==================================================================== - // Implements __contains__ for array types. - //==================================================================== - + /// + /// Implements __contains__ for array types. + /// public static int sq_contains(IntPtr ob, IntPtr v) { - CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob); + var obj = (CLRObject)GetManagedObject(ob); Type itemType = obj.inst.GetType().GetElementType(); - IList items = obj.inst as IList; + var items = obj.inst as IList; object value; if (!Converter.ToManaged(v, itemType, out value, false)) @@ -261,15 +246,14 @@ public static int sq_contains(IntPtr ob, IntPtr v) } - //==================================================================== - // Implements __len__ for array types. - //==================================================================== - + /// + /// Implements __len__ for array types. + /// public static int mp_length(IntPtr ob) { - CLRObject self = (CLRObject)ManagedType.GetManagedObject(ob); - Array items = self.inst as Array; + var self = (CLRObject)GetManagedObject(ob); + var items = self.inst as Array; return items.Length; } } -} \ No newline at end of file +} diff --git a/src/runtime/assemblyinfo.cs b/src/runtime/assemblyinfo.cs deleted file mode 100644 index 49433f0dc..000000000 --- a/src/runtime/assemblyinfo.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Reflection; -using System.Resources; -using System.Runtime.InteropServices; - -[assembly: AssemblyProduct("Python for .NET")] -[assembly: AssemblyVersion("4.0.0.1")] -[assembly: AssemblyDefaultAlias("Python.Runtime.dll")] -[assembly: CLSCompliant(true)] -[assembly: ComVisible(false)] -[assembly: AssemblyCopyright("MIT License")] -[assembly: AssemblyFileVersion("2.0.0.2")] -[assembly: NeutralResourcesLanguage("en")] - -#if PYTHON27 -[assembly: AssemblyTitle("Python.Runtime for Python 2.7")] -[assembly: AssemblyDescription("Python Runtime for Python 2.7")] -#endif -#if PYTHON33 -[assembly: AssemblyTitle("Python.Runtime for Python 3.3")] -[assembly: AssemblyDescription("Python Runtime for Python 3.3")] -#endif -#if PYTHON34 -[assembly: AssemblyTitle("Python.Runtime for Python 3.4")] -[assembly: AssemblyDescription("Python Runtime for Python 3.4")] -#endif -#if PYTHON35 -[assembly: AssemblyTitle("Python.Runtime for Python 3.5")] -[assembly: AssemblyDescription("Python Runtime for Python 3.5")] -#endif -#if PYTHON36 -[assembly: AssemblyTitle("Python.Runtime for Python 3.6")] -[assembly: AssemblyDescription("Python Runtime for Python 3.6")] -#endif diff --git a/src/runtime/assemblymanager.cs b/src/runtime/assemblymanager.cs index 5d9759375..d63930a58 100644 --- a/src/runtime/assemblymanager.cs +++ b/src/runtime/assemblymanager.cs @@ -1,9 +1,9 @@ using System; using System.Collections; -using System.IO; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Reflection; using System.Threading; @@ -17,33 +17,33 @@ internal class AssemblyManager { // modified from event handlers below, potentially triggered from different .NET threads // therefore this should be a ConcurrentDictionary - static ConcurrentDictionary> namespaces; - //static Dictionary> generics; - static AssemblyLoadEventHandler lhandler; - static ResolveEventHandler rhandler; + private static ConcurrentDictionary> namespaces; + //private static Dictionary> generics; + private static AssemblyLoadEventHandler lhandler; + private static ResolveEventHandler rhandler; + // updated only under GIL? - static Dictionary probed; + private static Dictionary probed; + // modified from event handlers below, potentially triggered from different .NET threads - static AssemblyList assemblies; + private static ConcurrentQueue assemblies; internal static List pypath; private AssemblyManager() { } - //=================================================================== - // Initialization performed on startup of the Python runtime. Here we - // scan all of the currently loaded assemblies to determine exported - // names, and register to be notified of new assembly loads. - //=================================================================== - + /// + /// Initialization performed on startup of the Python runtime. Here we + /// scan all of the currently loaded assemblies to determine exported + /// names, and register to be notified of new assembly loads. + /// internal static void Initialize() { - namespaces = new - ConcurrentDictionary>(); + namespaces = new ConcurrentDictionary>(); probed = new Dictionary(32); //generics = new Dictionary>(); - assemblies = new AssemblyList(16); + assemblies = new ConcurrentQueue(); pypath = new List(16); AppDomain domain = AppDomain.CurrentDomain; @@ -55,25 +55,24 @@ internal static void Initialize() domain.AssemblyResolve += rhandler; Assembly[] items = domain.GetAssemblies(); - foreach (var a in items) + foreach (Assembly a in items) { try { ScanAssembly(a); - assemblies.Add(a); + assemblies.Enqueue(a); } catch (Exception ex) { - Debug.WriteLine(string.Format("Error scanning assembly {0}. {1}", a, ex)); + Debug.WriteLine("Error scanning assembly {0}. {1}", a, ex); } } } - //=================================================================== - // Cleanup resources upon shutdown of the Python runtime. - //=================================================================== - + /// + /// Cleanup resources upon shutdown of the Python runtime. + /// internal static void Shutdown() { AppDomain domain = AppDomain.CurrentDomain; @@ -82,31 +81,29 @@ internal static void Shutdown() } - //=================================================================== - // Event handler for assembly load events. At the time the Python - // runtime loads, we scan the app domain to map the assemblies that - // are loaded at the time. We also have to register this event handler - // so that we can know about assemblies that get loaded after the - // Python runtime is initialized. - //=================================================================== - - static void AssemblyLoadHandler(Object ob, AssemblyLoadEventArgs args) + /// + /// Event handler for assembly load events. At the time the Python + /// runtime loads, we scan the app domain to map the assemblies that + /// are loaded at the time. We also have to register this event handler + /// so that we can know about assemblies that get loaded after the + /// Python runtime is initialized. + /// + private static void AssemblyLoadHandler(object ob, AssemblyLoadEventArgs args) { Assembly assembly = args.LoadedAssembly; - assemblies.Add(assembly); + assemblies.Enqueue(assembly); ScanAssembly(assembly); } - //=================================================================== - // Event handler for assembly resolve events. This is needed because - // we augment the assembly search path with the PYTHONPATH when we - // load an assembly from Python. Because of that, we need to listen - // for failed loads, because they might be dependencies of something - // we loaded from Python which also needs to be found on PYTHONPATH. - //=================================================================== - - static Assembly ResolveHandler(Object ob, ResolveEventArgs args) + /// + /// Event handler for assembly resolve events. This is needed because + /// we augment the assembly search path with the PYTHONPATH when we + /// load an assembly from Python. Because of that, we need to listen + /// for failed loads, because they might be dependencies of something + /// we loaded from Python which also needs to be found on PYTHONPATH. + /// + private static Assembly ResolveHandler(object ob, ResolveEventArgs args) { string name = args.Name.ToLower(); foreach (Assembly a in assemblies) @@ -121,19 +118,17 @@ static Assembly ResolveHandler(Object ob, ResolveEventArgs args) } - //=================================================================== - // We __really__ want to avoid using Python objects or APIs when - // probing for assemblies to load, since our ResolveHandler may be - // called in contexts where we don't have the Python GIL and can't - // even safely try to get it without risking a deadlock ;( - // - // To work around that, we update a managed copy of sys.path (which - // is the main thing we care about) when UpdatePath is called. The - // import hook calls this whenever it knows its about to use the - // assembly manager, which lets us keep up with changes to sys.path - // in a relatively lightweight and low-overhead way. - //=================================================================== - + /// + /// We __really__ want to avoid using Python objects or APIs when + /// probing for assemblies to load, since our ResolveHandler may be + /// called in contexts where we don't have the Python GIL and can't + /// even safely try to get it without risking a deadlock ;( + /// To work around that, we update a managed copy of sys.path (which + /// is the main thing we care about) when UpdatePath is called. The + /// import hook calls this whenever it knows its about to use the + /// assembly manager, which lets us keep up with changes to sys.path + /// in a relatively lightweight and low-overhead way. + /// internal static void UpdatePath() { IntPtr list = Runtime.PySys_GetObject("path"); @@ -142,7 +137,7 @@ internal static void UpdatePath() { pypath.Clear(); probed.Clear(); - for (int i = 0; i < count; i++) + for (var i = 0; i < count; i++) { IntPtr item = Runtime.PyList_GetItem(list, i); string path = Runtime.GetManagedString(item); @@ -155,21 +150,18 @@ internal static void UpdatePath() } - //=================================================================== - // Given an assembly name, try to find this assembly file using the - // PYTHONPATH. If not found, return null to indicate implicit load - // using standard load semantics (app base directory then GAC, etc.) - //=================================================================== - + /// + /// Given an assembly name, try to find this assembly file using the + /// PYTHONPATH. If not found, return null to indicate implicit load + /// using standard load semantics (app base directory then GAC, etc.) + /// public static string FindAssembly(string name) { char sep = Path.DirectorySeparatorChar; - string path; - string temp; - for (int i = 0; i < pypath.Count; i++) + foreach (string head in pypath) { - string head = pypath[i]; + string path; if (head == null || head.Length == 0) { path = name; @@ -179,11 +171,12 @@ public static string FindAssembly(string name) path = head + sep + name; } - temp = path + ".dll"; + string temp = path + ".dll"; if (File.Exists(temp)) { return temp; } + temp = path + ".exe"; if (File.Exists(temp)) { @@ -194,11 +187,10 @@ public static string FindAssembly(string name) } - //=================================================================== - // Loads an assembly from the application directory or the GAC - // given a simple assembly name. Returns the assembly if loaded. - //=================================================================== - + /// + /// Loads an assembly from the application directory or the GAC + /// given a simple assembly name. Returns the assembly if loaded. + /// public static Assembly LoadAssembly(string name) { Assembly assembly = null; @@ -206,9 +198,10 @@ public static Assembly LoadAssembly(string name) { assembly = Assembly.Load(name); } - catch (System.Exception e) + catch (Exception) { - //if (!(e is System.IO.FileNotFoundException)) { + //if (!(e is System.IO.FileNotFoundException)) + //{ // throw; //} } @@ -216,10 +209,9 @@ public static Assembly LoadAssembly(string name) } - //=================================================================== - // Loads an assembly using an augmented search path (the python path). - //=================================================================== - + /// + /// Loads an assembly using an augmented search path (the python path). + /// public static Assembly LoadAssemblyPath(string name) { string path = FindAssembly(name); @@ -230,7 +222,7 @@ public static Assembly LoadAssemblyPath(string name) { assembly = Assembly.LoadFrom(path); } - catch + catch (Exception) { } } @@ -248,14 +240,16 @@ public static Assembly LoadAssemblyFullPath(string name) if (Path.IsPathRooted(name)) { if (!Path.HasExtension(name)) + { name = name + ".dll"; + } if (File.Exists(name)) { try { assembly = Assembly.LoadFrom(name); } - catch + catch (Exception) { } } @@ -263,10 +257,9 @@ public static Assembly LoadAssemblyFullPath(string name) return assembly; } - //=================================================================== - // Returns an assembly that's already been loaded - //=================================================================== - + /// + /// Returns an assembly that's already been loaded + /// public static Assembly FindLoadedAssembly(string name) { foreach (Assembly a in assemblies) @@ -279,28 +272,29 @@ public static Assembly FindLoadedAssembly(string name) return null; } - //=================================================================== - // Given a qualified name of the form A.B.C.D, attempt to load - // an assembly named after each of A.B.C.D, A.B.C, A.B, A. This - // will only actually probe for the assembly once for each unique - // namespace. Returns true if any assemblies were loaded. - // TODO item 3 "* Deprecate implicit loading of assemblies": - // Set the fromFile flag if the name of the loaded assembly matches - // the fully qualified name that was requested if the framework - // actually loads an assembly. - // Call ONLY for namespaces that HAVE NOT been cached yet. - //=================================================================== - + /// + /// Given a qualified name of the form A.B.C.D, attempt to load + /// an assembly named after each of A.B.C.D, A.B.C, A.B, A. This + /// will only actually probe for the assembly once for each unique + /// namespace. Returns true if any assemblies were loaded. + /// + /// + /// TODO item 3 "* Deprecate implicit loading of assemblies": + /// Set the fromFile flag if the name of the loaded assembly matches + /// the fully qualified name that was requested if the framework + /// actually loads an assembly. + /// Call ONLY for namespaces that HAVE NOT been cached yet. + /// public static bool LoadImplicit(string name, bool warn = true) { string[] names = name.Split('.'); - bool loaded = false; - string s = ""; + var loaded = false; + var s = ""; Assembly lastAssembly = null; HashSet assembliesSet = null; - for (int i = 0; i < names.Length; i++) + for (var i = 0; i < names.Length; i++) { - s = (i == 0) ? names[0] : s + "." + names[i]; + s = i == 0 ? names[0] : s + "." + names[i]; if (!probed.ContainsKey(s)) { if (assembliesSet == null) @@ -328,10 +322,9 @@ public static bool LoadImplicit(string name, bool warn = true) // Deprecation warning if (warn && loaded) { - string deprWarning = String.Format( - "\nThe module was found, but not in a referenced namespace.\n" + - "Implicit loading is deprecated. Please use clr.AddReference(\"{0}\").", - Path.GetFileNameWithoutExtension(lastAssembly.Location)); + string location = Path.GetFileNameWithoutExtension(lastAssembly.Location); + string deprWarning = "The module was found, but not in a referenced namespace.\n" + + $"Implicit loading is deprecated. Please use clr.AddReference('{location}')."; Exceptions.deprecation(deprWarning); } @@ -339,13 +332,12 @@ public static bool LoadImplicit(string name, bool warn = true) } - //=================================================================== - // Scans an assembly for exported namespaces, adding them to the - // mapping of valid namespaces. Note that for a given namespace - // a.b.c.d, each of a, a.b, a.b.c and a.b.c.d are considered to - // be valid namespaces (to better match Python import semantics). - //=================================================================== - + /// + /// Scans an assembly for exported namespaces, adding them to the + /// mapping of valid namespaces. Note that for a given namespace + /// a.b.c.d, each of a, a.b, a.b.c and a.b.c.d are considered to + /// be valid namespaces (to better match Python import semantics). + /// internal static void ScanAssembly(Assembly assembly) { // A couple of things we want to do here: first, we want to @@ -353,24 +345,23 @@ internal static void ScanAssembly(Assembly assembly) // the assembly. Type[] types = assembly.GetTypes(); - for (int i = 0; i < types.Length; i++) + foreach (Type t in types) { - Type t = types[i]; string ns = t.Namespace ?? ""; if (!namespaces.ContainsKey(ns)) { string[] names = ns.Split('.'); - string s = ""; - for (int n = 0; n < names.Length; n++) + var s = ""; + for (var n = 0; n < names.Length; n++) { - s = (n == 0) ? names[0] : s + "." + names[n]; + s = n == 0 ? names[0] : s + "." + names[n]; namespaces.TryAdd(s, new ConcurrentDictionary()); } } if (ns != null) { - namespaces[ns].TryAdd(assembly, String.Empty); + namespaces[ns].TryAdd(assembly, string.Empty); } if (ns != null && t.IsGenericTypeDefinition) @@ -382,7 +373,7 @@ internal static void ScanAssembly(Assembly assembly) public static AssemblyName[] ListAssemblies() { - List names = new List(assemblies.Count); + var names = new List(assemblies.Count); foreach (Assembly assembly in assemblies) { names.Add(assembly.GetName()); @@ -390,36 +381,30 @@ public static AssemblyName[] ListAssemblies() return names.ToArray(); } - //=================================================================== - // Returns true if the given qualified name matches a namespace - // exported by an assembly loaded in the current app domain. - //=================================================================== - + /// + /// Returns true if the given qualified name matches a namespace + /// exported by an assembly loaded in the current app domain. + /// public static bool IsValidNamespace(string name) { - return !String.IsNullOrEmpty(name) && namespaces.ContainsKey(name); + return !string.IsNullOrEmpty(name) && namespaces.ContainsKey(name); } - //=================================================================== - // Returns list of assemblies that declare types in a given namespace - //=================================================================== - + /// + /// Returns list of assemblies that declare types in a given namespace + /// public static IEnumerable GetAssemblies(string nsname) { - if (!namespaces.ContainsKey(nsname)) - return new List(); - - return namespaces[nsname].Keys; + return !namespaces.ContainsKey(nsname) ? new List() : namespaces[nsname].Keys; } - //=================================================================== - // Returns the current list of valid names for the input namespace. - //=================================================================== - + /// + /// Returns the current list of valid names for the input namespace. + /// public static List GetNames(string nsname) { //Dictionary seen = new Dictionary(); - List names = new List(8); + var names = new List(8); List g = GenericUtil.GetGenericBaseNames(nsname); if (g != null) @@ -435,9 +420,8 @@ public static List GetNames(string nsname) foreach (Assembly a in namespaces[nsname].Keys) { Type[] types = a.GetTypes(); - for (int i = 0; i < types.Length; i++) + foreach (Type t in types) { - Type t = types[i]; if ((t.Namespace ?? "") == nsname) { names.Add(t.Name); @@ -460,12 +444,11 @@ public static List GetNames(string nsname) return names; } - //=================================================================== - // Returns the System.Type object for a given qualified name, - // looking in the currently loaded assemblies for the named - // type. Returns null if the named type cannot be found. - //=================================================================== - + /// + /// Returns the System.Type object for a given qualified name, + /// looking in the currently loaded assemblies for the named + /// type. Returns null if the named type cannot be found. + /// public static Type LookupType(string qname) { foreach (Assembly assembly in assemblies) @@ -478,92 +461,5 @@ public static Type LookupType(string qname) } return null; } - - /// - /// Wrapper around List for thread safe access - /// - private class AssemblyList : IEnumerable{ - private readonly List _list; - private readonly ReaderWriterLockSlim _lock; - - public AssemblyList(int capacity) { - _list = new List(capacity); - _lock = new ReaderWriterLockSlim(); - } - - public int Count - { - get - { - _lock.EnterReadLock(); - try { - return _list.Count; - } - finally { - _lock.ExitReadLock(); - } - } - } - - public void Add(Assembly assembly) { - _lock.EnterWriteLock(); - try - { - _list.Add(assembly); - } - finally - { - _lock.ExitWriteLock(); - } - } - - public IEnumerator GetEnumerator() - { - return ((IEnumerable) this).GetEnumerator(); - } - - /// - /// Enumerator wrapping around 's enumerator. - /// Acquires and releases a read lock on during enumeration - /// - private class Enumerator : IEnumerator - { - private readonly AssemblyList _assemblyList; - - private readonly IEnumerator _listEnumerator; - - public Enumerator(AssemblyList assemblyList) - { - _assemblyList = assemblyList; - _assemblyList._lock.EnterReadLock(); - _listEnumerator = _assemblyList._list.GetEnumerator(); - } - - public void Dispose() - { - _listEnumerator.Dispose(); - _assemblyList._lock.ExitReadLock(); - } - - public bool MoveNext() - { - return _listEnumerator.MoveNext(); - } - - public void Reset() - { - _listEnumerator.Reset(); - } - - public Assembly Current { get { return _listEnumerator.Current; } } - - object IEnumerator.Current { get { return Current; } } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return new Enumerator(this); - } - } } } diff --git a/src/runtime/classbase.cs b/src/runtime/classbase.cs index 3089465e3..4dd3b5364 100644 --- a/src/runtime/classbase.cs +++ b/src/runtime/classbase.cs @@ -1,7 +1,5 @@ using System; using System.Collections; -using System.Reflection; -using System.Security; using System.Runtime.InteropServices; namespace Python.Runtime @@ -19,7 +17,7 @@ internal class ClassBase : ManagedType internal Indexer indexer; internal Type type; - internal ClassBase(Type tp) : base() + internal ClassBase(Type tp) { indexer = null; type = tp; @@ -27,22 +25,20 @@ internal ClassBase(Type tp) : base() internal virtual bool CanSubclass() { - return (!this.type.IsEnum); + return !type.IsEnum; } - //==================================================================== - // Implements __init__ for reflected classes and value types. - //==================================================================== - + /// + /// Implements __init__ for reflected classes and value types. + /// public static int tp_init(IntPtr ob, IntPtr args, IntPtr kw) { return 0; } - //==================================================================== - // Default implementation of [] semantics for reflected types. - //==================================================================== - + /// + /// Default implementation of [] semantics for reflected types. + /// public virtual IntPtr type_subscript(IntPtr idx) { Type[] types = Runtime.PythonArgsToTypeArray(idx); @@ -51,12 +47,12 @@ public virtual IntPtr type_subscript(IntPtr idx) return Exceptions.RaiseTypeError("type(s) expected"); } - Type target = GenericUtil.GenericForType(this.type, types.Length); + Type target = GenericUtil.GenericForType(type, types.Length); if (target != null) { Type t = target.MakeGenericType(types); - ManagedType c = (ManagedType)ClassManager.GetClass(t); + ManagedType c = ClassManager.GetClass(t); Runtime.XIncref(c.pyHandle); return c.pyHandle; } @@ -64,11 +60,11 @@ public virtual IntPtr type_subscript(IntPtr idx) return Exceptions.RaiseTypeError("no type matches params"); } - //==================================================================== - // Standard comparison implementation for instances of reflected types. - //==================================================================== - - public static IntPtr tp_richcompare(IntPtr ob, IntPtr other, int op) { + /// + /// Standard comparison implementation for instances of reflected types. + /// + public static IntPtr tp_richcompare(IntPtr ob, IntPtr other, int op) + { CLRObject co1; CLRObject co2; switch (op) @@ -99,10 +95,10 @@ public static IntPtr tp_richcompare(IntPtr ob, IntPtr other, int op) { return pyfalse; } - Object o1 = co1.inst; - Object o2 = co2.inst; + object o1 = co1.inst; + object o2 = co2.inst; - if (Object.Equals(o1, o2)) + if (Equals(o1, o2)) { Runtime.XIncref(pytrue); return pytrue; @@ -116,14 +112,19 @@ public static IntPtr tp_richcompare(IntPtr ob, IntPtr other, int op) { case Runtime.Py_GE: co1 = GetManagedObject(ob) as CLRObject; co2 = GetManagedObject(other) as CLRObject; - if(co1 == null || co2 == null) + if (co1 == null || co2 == null) + { return Exceptions.RaiseTypeError("Cannot get managed object"); + } var co1Comp = co1.inst as IComparable; if (co1Comp == null) - return Exceptions.RaiseTypeError("Cannot convert object of type " + co1.GetType() + " to IComparable"); + { + Type co1Type = co1.GetType(); + return Exceptions.RaiseTypeError($"Cannot convert object of type {co1Type} to IComparable"); + } try { - var cmp = co1Comp.CompareTo(co2.inst); + int cmp = co1Comp.CompareTo(co2.inst); IntPtr pyCmp; if (cmp < 0) @@ -150,10 +151,12 @@ public static IntPtr tp_richcompare(IntPtr ob, IntPtr other, int op) { } else { - if (op == Runtime.Py_GE || op == Runtime.Py_GT) { + if (op == Runtime.Py_GE || op == Runtime.Py_GT) + { pyCmp = Runtime.PyTrue; } - else { + else + { pyCmp = Runtime.PyFalse; } } @@ -170,21 +173,20 @@ public static IntPtr tp_richcompare(IntPtr ob, IntPtr other, int op) { } } - //==================================================================== - // Standard iteration support for instances of reflected types. This - // allows natural iteration over objects that either are IEnumerable - // or themselves support IEnumerator directly. - //==================================================================== - + /// + /// Standard iteration support for instances of reflected types. This + /// allows natural iteration over objects that either are IEnumerable + /// or themselves support IEnumerator directly. + /// public static IntPtr tp_iter(IntPtr ob) { - CLRObject co = GetManagedObject(ob) as CLRObject; + var co = GetManagedObject(ob) as CLRObject; if (co == null) { return Exceptions.RaiseTypeError("invalid object"); } - IEnumerable e = co.inst as IEnumerable; + var e = co.inst as IEnumerable; IEnumerator o; if (e != null) @@ -197,8 +199,7 @@ public static IntPtr tp_iter(IntPtr ob) if (o == null) { - string message = "iteration over non-sequence"; - return Exceptions.RaiseTypeError(message); + return Exceptions.RaiseTypeError("iteration over non-sequence"); } } @@ -206,13 +207,12 @@ public static IntPtr tp_iter(IntPtr ob) } - //==================================================================== - // Standard __hash__ implementation for instances of reflected types. - //==================================================================== - + /// + /// Standard __hash__ implementation for instances of reflected types. + /// public static IntPtr tp_hash(IntPtr ob) { - CLRObject co = GetManagedObject(ob) as CLRObject; + var co = GetManagedObject(ob) as CLRObject; if (co == null) { return Exceptions.RaiseTypeError("unhashable type"); @@ -221,13 +221,12 @@ public static IntPtr tp_hash(IntPtr ob) } - //==================================================================== - // Standard __str__ implementation for instances of reflected types. - //==================================================================== - + /// + /// Standard __str__ implementation for instances of reflected types. + /// public static IntPtr tp_str(IntPtr ob) { - CLRObject co = GetManagedObject(ob) as CLRObject; + var co = GetManagedObject(ob) as CLRObject; if (co == null) { return Exceptions.RaiseTypeError("invalid object"); @@ -248,10 +247,9 @@ public static IntPtr tp_str(IntPtr ob) } - //==================================================================== - // Default implementations for required Python GC support. - //==================================================================== - + /// + /// Default implementations for required Python GC support. + /// public static int tp_traverse(IntPtr ob, IntPtr func, IntPtr args) { return 0; @@ -267,10 +265,9 @@ public static int tp_is_gc(IntPtr type) return 1; } - //==================================================================== - // Standard dealloc implementation for instances of reflected types. - //==================================================================== - + /// + /// Standard dealloc implementation for instances of reflected types. + /// public static void tp_dealloc(IntPtr ob) { ManagedType self = GetManagedObject(ob); @@ -285,4 +282,4 @@ public static void tp_dealloc(IntPtr ob) self.gcHandle.Free(); } } -} \ No newline at end of file +} diff --git a/src/runtime/classderived.cs b/src/runtime/classderived.cs index 02d734c26..16d3b99db 100644 --- a/src/runtime/classderived.cs +++ b/src/runtime/classderived.cs @@ -1,10 +1,8 @@ -using System; -using System.IO; -using System.Reflection; -using System.Reflection.Emit; +using System; using System.Collections.Generic; -using System.Threading; using System.Linq; +using System.Reflection; +using System.Reflection.Emit; using System.Runtime.InteropServices; using System.Threading.Tasks; @@ -16,16 +14,17 @@ namespace Python.Runtime /// Python type objects. Each of those type objects is associated with /// an instance of ClassObject, which provides its implementation. /// - - // interface used to idenfity which C# types were dynamically created as python subclasses + /// + /// interface used to identify which C# types were dynamically created as python subclasses + /// public interface IPythonDerivedType { } internal class ClassDerivedObject : ClassObject { - static private Dictionary assemblyBuilders; - static private Dictionary, ModuleBuilder> moduleBuilders; + private static Dictionary assemblyBuilders; + private static Dictionary, ModuleBuilder> moduleBuilders; static ClassDerivedObject() { @@ -33,31 +32,32 @@ static ClassDerivedObject() moduleBuilders = new Dictionary, ModuleBuilder>(); } - internal ClassDerivedObject(Type tp) - : base(tp) + internal ClassDerivedObject(Type tp) : base(tp) { } /// /// Implements __new__ for derived classes of reflected classes. - /// - new public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) + /// + public new static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { - ClassDerivedObject cls = GetManagedObject(tp) as ClassDerivedObject; + var cls = GetManagedObject(tp) as ClassDerivedObject; // call the managed constructor - Object obj = cls.binder.InvokeRaw(IntPtr.Zero, args, kw); + object obj = cls.binder.InvokeRaw(IntPtr.Zero, args, kw); if (obj == null) + { return IntPtr.Zero; + } // return the pointer to the python object // (this indirectly calls ClassDerivedObject.ToPython) return Converter.ToPython(obj, cls.GetType()); } - new public static void tp_dealloc(IntPtr ob) + public new static void tp_dealloc(IntPtr ob) { - CLRObject self = (CLRObject)GetManagedObject(ob); + var self = (CLRObject)GetManagedObject(ob); // don't let the python GC destroy this object Runtime.PyObject_GC_UnTrack(self.pyHandle); @@ -72,14 +72,16 @@ internal ClassDerivedObject(Type tp) self.gcHandle = gc; } - // Called from Converter.ToPython for types that are python subclasses of managed types. - // The referenced python object is returned instead of a new wrapper. + /// + /// Called from Converter.ToPython for types that are python subclasses of managed types. + /// The referenced python object is returned instead of a new wrapper. + /// internal static IntPtr ToPython(IPythonDerivedType obj) { // derived types have a __pyobj__ field that gets set to the python - // object in the overriden constructor + // object in the overridden constructor FieldInfo fi = obj.GetType().GetField("__pyobj__"); - CLRObject self = (CLRObject)fi.GetValue(obj); + var self = (CLRObject)fi.GetValue(obj); Runtime.XIncref(self.pyHandle); @@ -104,8 +106,8 @@ internal static IntPtr ToPython(IPythonDerivedType obj) /// /// Creates a new managed type derived from a base type with any virtual - /// methods overriden to call out to python if the associated python - /// object has overriden the method. + /// methods overridden to call out to python if the associated python + /// object has overridden the method. /// internal static Type CreateDerivedType(string name, Type baseType, @@ -115,31 +117,35 @@ internal static Type CreateDerivedType(string name, string moduleName = "Python.Runtime.Dynamic.dll") { if (null != namespaceStr) + { name = namespaceStr + "." + name; + } if (null == assemblyName) + { assemblyName = Assembly.GetExecutingAssembly().FullName; + } ModuleBuilder moduleBuilder = GetModuleBuilder(assemblyName, moduleName); - TypeBuilder typeBuilder; Type baseClass = baseType; - List interfaces = new List { typeof(IPythonDerivedType) }; + var interfaces = new List { typeof(IPythonDerivedType) }; // if the base type is an interface then use System.Object as the base class // and add the base type to the list of interfaces this new class will implement. if (baseType.IsInterface) { interfaces.Add(baseType); - baseClass = typeof(System.Object); + baseClass = typeof(object); } - typeBuilder = moduleBuilder.DefineType(name, + TypeBuilder typeBuilder = moduleBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.Class, baseClass, interfaces.ToArray()); // add a field for storing the python object pointer + // FIXME: fb not used FieldBuilder fb = typeBuilder.DefineField("__pyobj__", typeof(CLRObject), FieldAttributes.Public); // override any constructors @@ -149,17 +155,18 @@ internal static Type CreateDerivedType(string name, AddConstructor(ctor, baseType, typeBuilder); } - // Override any properties explicitly overriden in python - HashSet pyProperties = new HashSet(); + // Override any properties explicitly overridden in python + var pyProperties = new HashSet(); if (py_dict != IntPtr.Zero && Runtime.PyDict_Check(py_dict)) { Runtime.XIncref(py_dict); - using (PyDict dict = new PyDict(py_dict)) + using (var dict = new PyDict(py_dict)) using (PyObject keys = dict.Keys()) { foreach (PyObject pyKey in keys) { using (PyObject value = dict[pyKey]) + { if (value.HasAttr("_clr_property_type_")) { string propertyName = pyKey.ToString(); @@ -168,23 +175,28 @@ internal static Type CreateDerivedType(string name, // Add the property to the type AddPythonProperty(propertyName, value, typeBuilder); } + } } } } - // override any virtual methods not already overriden by the properties above + // override any virtual methods not already overridden by the properties above MethodInfo[] methods = baseType.GetMethods(); - HashSet virtualMethods = new HashSet(); + var virtualMethods = new HashSet(); foreach (MethodInfo method in methods) { if (!method.Attributes.HasFlag(MethodAttributes.Virtual) | method.Attributes.HasFlag(MethodAttributes.Final)) + { continue; + } - // skip if this property has already been overriden + // skip if this property has already been overridden if ((method.Name.StartsWith("get_") || method.Name.StartsWith("set_")) && pyProperties.Contains(method.Name.Substring(4))) + { continue; + } // keep track of the virtual methods redirected to the python instance virtualMethods.Add(method.Name); @@ -197,23 +209,27 @@ internal static Type CreateDerivedType(string name, if (py_dict != IntPtr.Zero && Runtime.PyDict_Check(py_dict)) { Runtime.XIncref(py_dict); - using (PyDict dict = new PyDict(py_dict)) + using (var dict = new PyDict(py_dict)) using (PyObject keys = dict.Keys()) { foreach (PyObject pyKey in keys) { using (PyObject value = dict[pyKey]) + { if (value.HasAttr("_clr_return_type_") && value.HasAttr("_clr_arg_types_")) { string methodName = pyKey.ToString(); // if this method has already been redirected to the python method skip it if (virtualMethods.Contains(methodName)) + { continue; + } // Add the method to the type AddPythonMethod(methodName, value, typeBuilder); } + } } } } @@ -239,6 +255,7 @@ internal static Type CreateDerivedType(string name, Assembly assembly = Assembly.GetAssembly(type); AssemblyManager.ScanAssembly(assembly); + // FIXME: assemblyBuilder not used AssemblyBuilder assemblyBuilder = assemblyBuilders[assemblyName]; return type; @@ -267,8 +284,10 @@ private static void AddConstructor(ConstructorInfo ctor, Type baseType, TypeBuil // emit the assembly for calling the original method using call instead of callvirt ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); - for (int i = 0; i < parameters.Length; ++i) + for (var i = 0; i < parameters.Length; ++i) + { il.Emit(OpCodes.Ldarg, i + 1); + } il.Emit(OpCodes.Call, ctor); il.Emit(OpCodes.Ret); @@ -279,20 +298,22 @@ private static void AddConstructor(ConstructorInfo ctor, Type baseType, TypeBuil ctor.CallingConvention, parameterTypes); il = cb.GetILGenerator(); - il.DeclareLocal(typeof(Object[])); + il.DeclareLocal(typeof(object[])); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, baseCtorName); il.Emit(OpCodes.Ldc_I4, parameters.Length); - il.Emit(OpCodes.Newarr, typeof(System.Object)); + il.Emit(OpCodes.Newarr, typeof(object)); il.Emit(OpCodes.Stloc_0); - for (int i = 0; i < parameters.Length; ++i) + for (var i = 0; i < parameters.Length; ++i) { il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldc_I4, i); il.Emit(OpCodes.Ldarg, i + 1); if (parameterTypes[i].IsValueType) + { il.Emit(OpCodes.Box, parameterTypes[i]); - il.Emit(OpCodes.Stelem, typeof(Object)); + } + il.Emit(OpCodes.Stelem, typeof(object)); } il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeCtor")); @@ -303,7 +324,7 @@ private static void AddConstructor(ConstructorInfo ctor, Type baseType, TypeBuil /// Add a virtual method override that checks for an override on the python instance /// and calls it, otherwise fall back to the base class method. /// - /// virtual method to be overriden + /// virtual method to be overridden /// Python callable object /// TypeBuilder for the new type the method is to be added to private static void AddVirtualMethod(MethodInfo method, Type baseType, TypeBuilder typeBuilder) @@ -326,8 +347,10 @@ private static void AddVirtualMethod(MethodInfo method, Type baseType, TypeBuild // emit the assembly for calling the original method using call instead of callvirt ILGenerator baseIl = baseMethodBuilder.GetILGenerator(); baseIl.Emit(OpCodes.Ldarg_0); - for (int i = 0; i < parameters.Length; ++i) + for (var i = 0; i < parameters.Length; ++i) + { baseIl.Emit(OpCodes.Ldarg, i + 1); + } baseIl.Emit(OpCodes.Call, method); baseIl.Emit(OpCodes.Ret); } @@ -342,27 +365,33 @@ private static void AddVirtualMethod(MethodInfo method, Type baseType, TypeBuild method.ReturnType, parameterTypes); ILGenerator il = methodBuilder.GetILGenerator(); - il.DeclareLocal(typeof(Object[])); + il.DeclareLocal(typeof(object[])); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, method.Name); // don't fall back to the base type's method if it's abstract if (null != baseMethodName) + { il.Emit(OpCodes.Ldstr, baseMethodName); + } else + { il.Emit(OpCodes.Ldnull); + } il.Emit(OpCodes.Ldc_I4, parameters.Length); - il.Emit(OpCodes.Newarr, typeof(System.Object)); + il.Emit(OpCodes.Newarr, typeof(object)); il.Emit(OpCodes.Stloc_0); - for (int i = 0; i < parameters.Length; ++i) + for (var i = 0; i < parameters.Length; ++i) { il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldc_I4, i); il.Emit(OpCodes.Ldarg, i + 1); if (parameterTypes[i].IsValueType) + { il.Emit(OpCodes.Box, parameterTypes[i]); - il.Emit(OpCodes.Stelem, typeof(Object)); + } + il.Emit(OpCodes.Stelem, typeof(object)); } il.Emit(OpCodes.Ldloc_0); if (method.ReturnType == typeof(void)) @@ -379,9 +408,9 @@ private static void AddVirtualMethod(MethodInfo method, Type baseType, TypeBuild /// /// Python method may have the following function attributes set to control how they're exposed: - /// - _clr_return_type_ - method return type (required) - /// - _clr_arg_types_ - list of method argument types (required) - /// - _clr_method_name_ - method name, if different from the python method name (optional) + /// - _clr_return_type_ - method return type (required) + /// - _clr_arg_types_ - list of method argument types (required) + /// - _clr_method_name_ - method name, if different from the python method name (optional) /// /// Method name to add to the type /// Python callable object @@ -391,25 +420,33 @@ private static void AddPythonMethod(string methodName, PyObject func, TypeBuilde if (func.HasAttr("_clr_method_name_")) { using (PyObject pyMethodName = func.GetAttr("_clr_method_name_")) + { methodName = pyMethodName.ToString(); + } } using (PyObject pyReturnType = func.GetAttr("_clr_return_type_")) using (PyObject pyArgTypes = func.GetAttr("_clr_arg_types_")) { - Type returnType = pyReturnType.AsManagedObject(typeof(Type)) as Type; + var returnType = pyReturnType.AsManagedObject(typeof(Type)) as Type; if (returnType == null) + { returnType = typeof(void); + } if (!pyArgTypes.IsIterable()) + { throw new ArgumentException("_clr_arg_types_ must be a list or tuple of CLR types"); + } - List argTypes = new List(); + var argTypes = new List(); foreach (PyObject pyArgType in pyArgTypes) { - Type argType = pyArgType.AsManagedObject(typeof(Type)) as Type; + var argType = pyArgType.AsManagedObject(typeof(Type)) as Type; if (argType == null) + { throw new ArgumentException("_clr_arg_types_ must be a list or tuple of CLR types"); + } argTypes.Add(argType); } @@ -425,21 +462,23 @@ private static void AddPythonMethod(string methodName, PyObject func, TypeBuilde argTypes.ToArray()); ILGenerator il = methodBuilder.GetILGenerator(); - il.DeclareLocal(typeof(Object[])); + il.DeclareLocal(typeof(object[])); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldstr, methodName); il.Emit(OpCodes.Ldnull); // don't fall back to the base type's method il.Emit(OpCodes.Ldc_I4, argTypes.Count); - il.Emit(OpCodes.Newarr, typeof(System.Object)); + il.Emit(OpCodes.Newarr, typeof(object)); il.Emit(OpCodes.Stloc_0); - for (int i = 0; i < argTypes.Count; ++i) + for (var i = 0; i < argTypes.Count; ++i) { il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldc_I4, i); il.Emit(OpCodes.Ldarg, i + 1); if (argTypes[i].IsValueType) + { il.Emit(OpCodes.Box, argTypes[i]); - il.Emit(OpCodes.Stelem, typeof(Object)); + } + il.Emit(OpCodes.Stelem, typeof(object)); } il.Emit(OpCodes.Ldloc_0); if (returnType == typeof(void)) @@ -457,7 +496,7 @@ private static void AddPythonMethod(string methodName, PyObject func, TypeBuilde /// /// Python properties may have the following function attributes set to control how they're exposed: - /// - _clr_property_type_ - property type (required) + /// - _clr_property_type_ - property type (required) /// /// Property name to add to the type /// Python property object @@ -473,9 +512,11 @@ private static void AddPythonProperty(string propertyName, PyObject func, TypeBu using (PyObject pyPropertyType = func.GetAttr("_clr_property_type_")) { - Type propertyType = pyPropertyType.AsManagedObject(typeof(Type)) as Type; + var propertyType = pyPropertyType.AsManagedObject(typeof(Type)) as Type; if (propertyType == null) + { throw new ArgumentException("_clr_property_type must be a CLR type"); + } PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, @@ -485,6 +526,7 @@ private static void AddPythonProperty(string propertyName, PyObject func, TypeBu if (func.HasAttr("fget")) { using (PyObject pyfget = func.GetAttr("fget")) + { if (pyfget.IsTrue()) { MethodBuilder methodBuilder = typeBuilder.DefineMethod("get_" + propertyName, @@ -501,17 +543,19 @@ private static void AddPythonProperty(string propertyName, PyObject func, TypeBu propertyBuilder.SetGetMethod(methodBuilder); } + } } if (func.HasAttr("fset")) { using (PyObject pyset = func.GetAttr("fset")) + { if (pyset.IsTrue()) { MethodBuilder methodBuilder = typeBuilder.DefineMethod("set_" + propertyName, methodAttribs, null, - new Type[] { propertyType }); + new[] { propertyType }); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); @@ -523,6 +567,7 @@ private static void AddPythonProperty(string propertyName, PyObject func, TypeBu propertyBuilder.SetSetMethod(methodBuilder); } + } } } } @@ -531,7 +576,7 @@ private static ModuleBuilder GetModuleBuilder(string assemblyName, string module { // find or create a dynamic assembly and module AppDomain domain = AppDomain.CurrentDomain; - ModuleBuilder moduleBuilder = null; + ModuleBuilder moduleBuilder; if (moduleBuilders.ContainsKey(Tuple.Create(assemblyName, moduleName))) { @@ -539,7 +584,7 @@ private static ModuleBuilder GetModuleBuilder(string assemblyName, string module } else { - AssemblyBuilder assemblyBuilder = null; + AssemblyBuilder assemblyBuilder; if (assemblyBuilders.ContainsKey(assemblyName)) { assemblyBuilder = assemblyBuilders[assemblyName]; @@ -559,53 +604,54 @@ private static ModuleBuilder GetModuleBuilder(string assemblyName, string module } } - // - // PythonDerivedType contains static methods used by the dynamically created - // derived type that allow it to call back into python from overriden virtual - // methods, and also handle the construction and destruction of the python - // object. - // - // This has to be public as it's called from methods on dynamically built classes - // potentially in other assemblies. - // + /// + /// PythonDerivedType contains static methods used by the dynamically created + /// derived type that allow it to call back into python from overridden virtual + /// methods, and also handle the construction and destruction of the python + /// object. + /// + /// + /// This has to be public as it's called from methods on dynamically built classes + /// potentially in other assemblies. + /// public class PythonDerivedType { - //==================================================================== - // This is the implementaion of the overriden methods in the derived - // type. It looks for a python method with the same name as the method - // on the managed base class and if it exists and isn't the managed - // method binding (ie it has been overriden in the derived python - // class) it calls it, otherwise it calls the base method. - //==================================================================== - public static T InvokeMethod(IPythonDerivedType obj, string methodName, string origMethodName, Object[] args) + /// + /// This is the implementation of the overridden methods in the derived + /// type. It looks for a python method with the same name as the method + /// on the managed base class and if it exists and isn't the managed + /// method binding (i.e. it has been overridden in the derived python + /// class) it calls it, otherwise it calls the base method. + /// + public static T InvokeMethod(IPythonDerivedType obj, string methodName, string origMethodName, object[] args) { FieldInfo fi = obj.GetType().GetField("__pyobj__"); - CLRObject self = (CLRObject)fi.GetValue(obj); + var self = (CLRObject)fi.GetValue(obj); if (null != self) { - List disposeList = new List(); + var disposeList = new List(); IntPtr gs = Runtime.PyGILState_Ensure(); try { Runtime.XIncref(self.pyHandle); - PyObject pyself = new PyObject(self.pyHandle); + var pyself = new PyObject(self.pyHandle); disposeList.Add(pyself); Runtime.XIncref(Runtime.PyNone); - PyObject pynone = new PyObject(Runtime.PyNone); + var pynone = new PyObject(Runtime.PyNone); disposeList.Add(pynone); PyObject method = pyself.GetAttr(methodName, pynone); disposeList.Add(method); if (method.Handle != Runtime.PyNone) { - // if the method hasn't been overriden then it will be a managed object + // if the method hasn't been overridden then it will be a managed object ManagedType managedMethod = ManagedType.GetManagedObject(method.Handle); if (null == managedMethod) { - PyObject[] pyargs = new PyObject[args.Length]; - for (int i = 0; i < args.Length; ++i) + var pyargs = new PyObject[args.Length]; + for (var i = 0; i < args.Length; ++i) { pyargs[i] = new PyObject(Converter.ToPythonImplicit(args[i])); disposeList.Add(pyargs[i]); @@ -621,15 +667,16 @@ public static T InvokeMethod(IPythonDerivedType obj, string methodName, strin { foreach (PyObject x in disposeList) { - if (x != null) - x.Dispose(); + x?.Dispose(); } Runtime.PyGILState_Release(gs); } } if (origMethodName == null) + { throw new NotImplementedException("Python object does not have a '" + methodName + "' method"); + } return (T)obj.GetType().InvokeMember(origMethodName, BindingFlags.InvokeMethod, @@ -639,34 +686,34 @@ public static T InvokeMethod(IPythonDerivedType obj, string methodName, strin } public static void InvokeMethodVoid(IPythonDerivedType obj, string methodName, string origMethodName, - Object[] args) + object[] args) { FieldInfo fi = obj.GetType().GetField("__pyobj__"); - CLRObject self = (CLRObject)fi.GetValue(obj); + var self = (CLRObject)fi.GetValue(obj); if (null != self) { - List disposeList = new List(); + var disposeList = new List(); IntPtr gs = Runtime.PyGILState_Ensure(); try { Runtime.XIncref(self.pyHandle); - PyObject pyself = new PyObject(self.pyHandle); + var pyself = new PyObject(self.pyHandle); disposeList.Add(pyself); Runtime.XIncref(Runtime.PyNone); - PyObject pynone = new PyObject(Runtime.PyNone); + var pynone = new PyObject(Runtime.PyNone); disposeList.Add(pynone); PyObject method = pyself.GetAttr(methodName, pynone); disposeList.Add(method); if (method.Handle != Runtime.PyNone) { - // if the method hasn't been overriden then it will be a managed object + // if the method hasn't been overridden then it will be a managed object ManagedType managedMethod = ManagedType.GetManagedObject(method.Handle); if (null == managedMethod) { - PyObject[] pyargs = new PyObject[args.Length]; - for (int i = 0; i < args.Length; ++i) + var pyargs = new PyObject[args.Length]; + for (var i = 0; i < args.Length; ++i) { pyargs[i] = new PyObject(Converter.ToPythonImplicit(args[i])); disposeList.Add(pyargs[i]); @@ -682,15 +729,16 @@ public static void InvokeMethodVoid(IPythonDerivedType obj, string methodName, s { foreach (PyObject x in disposeList) { - if (x != null) - x.Dispose(); + x?.Dispose(); } Runtime.PyGILState_Release(gs); } } if (origMethodName == null) - throw new NotImplementedException("Python object does not have a '" + methodName + "' method"); + { + throw new NotImplementedException($"Python object does not have a '{methodName}' method"); + } obj.GetType().InvokeMember(origMethodName, BindingFlags.InvokeMethod, @@ -702,18 +750,22 @@ public static void InvokeMethodVoid(IPythonDerivedType obj, string methodName, s public static T InvokeGetProperty(IPythonDerivedType obj, string propertyName) { FieldInfo fi = obj.GetType().GetField("__pyobj__"); - CLRObject self = (CLRObject)fi.GetValue(obj); + var self = (CLRObject)fi.GetValue(obj); if (null == self) + { throw new NullReferenceException("Instance must be specified when getting a property"); + } IntPtr gs = Runtime.PyGILState_Ensure(); try { Runtime.XIncref(self.pyHandle); - using (PyObject pyself = new PyObject(self.pyHandle)) + using (var pyself = new PyObject(self.pyHandle)) using (PyObject pyvalue = pyself.GetAttr(propertyName)) + { return (T)pyvalue.AsManagedObject(typeof(T)); + } } finally { @@ -724,18 +776,22 @@ public static T InvokeGetProperty(IPythonDerivedType obj, string propertyName public static void InvokeSetProperty(IPythonDerivedType obj, string propertyName, T value) { FieldInfo fi = obj.GetType().GetField("__pyobj__"); - CLRObject self = (CLRObject)fi.GetValue(obj); + var self = (CLRObject)fi.GetValue(obj); if (null == self) + { throw new NullReferenceException("Instance must be specified when setting a property"); + } IntPtr gs = Runtime.PyGILState_Ensure(); try { Runtime.XIncref(self.pyHandle); - using (PyObject pyself = new PyObject(self.pyHandle)) - using (PyObject pyvalue = new PyObject(Converter.ToPythonImplicit(value))) + using (var pyself = new PyObject(self.pyHandle)) + using (var pyvalue = new PyObject(Converter.ToPythonImplicit(value))) + { pyself.SetAttr(propertyName, pyvalue); + } } finally { @@ -743,7 +799,7 @@ public static void InvokeSetProperty(IPythonDerivedType obj, string propertyN } } - public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, Object[] args) + public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, object[] args) { // call the base constructor obj.GetType().InvokeMember(origCtorName, @@ -752,7 +808,6 @@ public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, Objec obj, args); - List disposeList = new List(); CLRObject self = null; IntPtr gs = Runtime.PyGILState_Ensure(); try @@ -765,48 +820,16 @@ public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, Objec // object to be collected. FieldInfo fi = obj.GetType().GetField("__pyobj__"); fi.SetValue(obj, self); - - Runtime.XIncref(self.pyHandle); - PyObject pyself = new PyObject(self.pyHandle); - disposeList.Add(pyself); - - Runtime.XIncref(Runtime.PyNone); - PyObject pynone = new PyObject(Runtime.PyNone); - disposeList.Add(pynone); - - // call __init__ - PyObject init = pyself.GetAttr("__init__", pynone); - disposeList.Add(init); - if (init.Handle != Runtime.PyNone) - { - // if __init__ hasn't been overriden then it will be a managed object - ManagedType managedMethod = ManagedType.GetManagedObject(init.Handle); - if (null == managedMethod) - { - PyObject[] pyargs = new PyObject[args.Length]; - for (int i = 0; i < args.Length; ++i) - { - pyargs[i] = new PyObject(Converter.ToPython(args[i], args[i]?.GetType())); - disposeList.Add(pyargs[i]); - } - - disposeList.Add(init.Invoke(pyargs)); - } - } } finally { - foreach (PyObject x in disposeList) - { - if (x != null) - x.Dispose(); - } - // Decrement the python object's reference count. // This doesn't actually destroy the object, it just sets the reference to this object // to be a weak reference and it will be destroyed when the C# object is destroyed. if (null != self) + { Runtime.XDecref(self.pyHandle); + } Runtime.PyGILState_Release(gs); } @@ -815,7 +838,7 @@ public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, Objec public static void Finalize(IPythonDerivedType obj) { FieldInfo fi = obj.GetType().GetField("__pyobj__"); - CLRObject self = (CLRObject)fi.GetValue(obj); + var self = (CLRObject)fi.GetValue(obj); // If python's been terminated then just free the gchandle. lock (Runtime.IsFinalizingLock) @@ -827,9 +850,10 @@ public static void Finalize(IPythonDerivedType obj) } } - // delete the python object in an asnyc task as we may not be able to acquire + // delete the python object in an async task as we may not be able to acquire // the GIL immediately and we don't want to block the GC thread. - var t = Task.Factory.StartNew(() => + // FIXME: t isn't used + Task t = Task.Factory.StartNew(() => { lock (Runtime.IsFinalizingLock) { @@ -848,7 +872,9 @@ public static void Finalize(IPythonDerivedType obj) // python object. IntPtr dict = Marshal.ReadIntPtr(self.pyHandle, ObjectOffset.DictOffset(self.pyHandle)); if (dict != IntPtr.Zero) + { Runtime.XDecref(dict); + } Runtime.PyObject_GC_Del(self.pyHandle); self.gcHandle.Free(); } diff --git a/src/runtime/classmanager.cs b/src/runtime/classmanager.cs index 52fecf39c..6a9d40ebd 100644 --- a/src/runtime/classmanager.cs +++ b/src/runtime/classmanager.cs @@ -1,8 +1,8 @@ using System; -using System.Runtime.InteropServices; -using System.Collections.Generic; using System.Collections; +using System.Collections.Generic; using System.Reflection; +using System.Runtime.InteropServices; using System.Security; namespace Python.Runtime @@ -10,7 +10,6 @@ namespace Python.Runtime /// /// The ClassManager is responsible for creating and managing instances /// that implement the Python type objects that reflect managed classes. - /// /// Each managed type reflected to Python is represented by an instance /// of a concrete subclass of ClassBase. Each instance is associated with /// a generated Python type object, whose slots point to static methods @@ -18,8 +17,8 @@ namespace Python.Runtime /// internal class ClassManager { - static Dictionary cache; - static Type dtype; + private static Dictionary cache; + private static Type dtype; private ClassManager() { @@ -28,18 +27,17 @@ private ClassManager() static ClassManager() { cache = new Dictionary(128); - // SEE: http://msdn.microsoft.com/en-us/library/96b1ayy4%28VS.90%29.aspx + // SEE: https://msdn.microsoft.com/en-us/library/96b1ayy4(v=vs.100).aspx // ""All delegates inherit from MulticastDelegate, which inherits from Delegate."" // Was Delegate, which caused a null MethodInfo returned from GetMethode("Invoke") // and crashed on Linux under Mono. - dtype = typeof(System.MulticastDelegate); + dtype = typeof(MulticastDelegate); } - //==================================================================== - // Return the ClassBase-derived instance that implements a particular - // reflected managed type, creating it if it doesn't yet exist. - //==================================================================== - + /// + /// Return the ClassBase-derived instance that implements a particular + /// reflected managed type, creating it if it doesn't yet exist. + /// internal static ClassBase GetClass(Type type) { ClassBase cb = null; @@ -50,18 +48,18 @@ internal static ClassBase GetClass(Type type) } cb = CreateClass(type); cache.Add(type, cb); - // Initialize the object later, as this might call this GetClass method recursivly (for example when a nested class inherits its declaring class...) + // Initialize the object later, as this might call this GetClass method + // recursively (for example when a nested class inherits its declaring class...) InitClassBase(type, cb); return cb; } - //==================================================================== - // Create a new ClassBase-derived instance that implements a reflected - // managed type. The new object will be associated with a generated - // Python type object. - //==================================================================== - + /// + /// Create a new ClassBase-derived instance that implements a reflected + /// managed type. The new object will be associated with a generated + /// Python type object. + /// private static ClassBase CreateClass(Type type) { // Next, select the appropriate managed implementation class. @@ -140,30 +138,29 @@ private static void InitClassBase(Type type, ClassBase impl) IDictionaryEnumerator iter = info.members.GetEnumerator(); while (iter.MoveNext()) { - ManagedType item = (ManagedType)iter.Value; - string name = (string)iter.Key; + var item = (ManagedType)iter.Value; + var name = (string)iter.Key; Runtime.PyDict_SetItemString(dict, name, item.pyHandle); } // If class has constructors, generate an __doc__ attribute. - IntPtr doc = IntPtr.Zero; Type marker = typeof(DocStringAttribute); - Attribute[] attrs = (Attribute[])type.GetCustomAttributes(marker, false); + var attrs = (Attribute[])type.GetCustomAttributes(marker, false); if (attrs.Length == 0) { doc = IntPtr.Zero; } else { - DocStringAttribute attr = (DocStringAttribute)attrs[0]; + var attr = (DocStringAttribute)attrs[0]; string docStr = attr.DocString; doc = Runtime.PyString_FromString(docStr); Runtime.PyDict_SetItemString(dict, "__doc__", doc); Runtime.XDecref(doc); } - ClassObject co = impl as ClassObject; + var co = impl as ClassObject; // If this is a ClassObject AND it has constructors, generate a __doc__ attribute. // required that the ClassObject.ctors be changed to internal if (co != null) @@ -173,9 +170,9 @@ private static void InitClassBase(Type type, ClassBase impl) // Implement Overloads on the class object if (!CLRModule._SuppressOverloads) { - ConstructorBinding ctors = new ConstructorBinding(type, tp, co.binder); + var ctors = new ConstructorBinding(type, tp, co.binder); // ExtensionType types are untracked, so don't Incref() them. - // XXX deprecate __overloads__ soon... + // TODO: deprecate __overloads__ soon... Runtime.PyDict_SetItemString(dict, "__overloads__", ctors.pyHandle); Runtime.PyDict_SetItemString(dict, "Overloads", ctors.pyHandle); } @@ -189,18 +186,17 @@ private static void InitClassBase(Type type, ClassBase impl) } } } - } private static ClassInfo GetClassInfo(Type type) { - ClassInfo ci = new ClassInfo(type); - Hashtable methods = new Hashtable(); + var ci = new ClassInfo(type); + var methods = new Hashtable(); ArrayList list; MethodInfo meth; ManagedType ob; - String name; - Object item; + string name; + object item; Type tp; int i, n; @@ -210,15 +206,14 @@ private static ClassInfo GetClassInfo(Type type) // method and a class B that defines two more. The name-based // descriptor Python will find needs to know about inherited // overloads as well as those declared on the sub class. - BindingFlags flags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; MemberInfo[] info = type.GetMembers(flags); - Hashtable local = new Hashtable(); - ArrayList items = new ArrayList(); + var local = new Hashtable(); + var items = new ArrayList(); MemberInfo m; // Loop through once to find out which names are declared @@ -273,7 +268,7 @@ private static ClassInfo GetClassInfo(Type type) for (i = 0; i < items.Count; i++) { - MemberInfo mi = (MemberInfo)items[i]; + var mi = (MemberInfo)items[i]; switch (mi.MemberType) { @@ -281,7 +276,9 @@ private static ClassInfo GetClassInfo(Type type) meth = (MethodInfo)mi; if (!(meth.IsPublic || meth.IsFamily || meth.IsFamilyOrAssembly)) + { continue; + } name = meth.Name; item = methods[name]; if (item == null) @@ -293,7 +290,7 @@ private static ClassInfo GetClassInfo(Type type) continue; case MemberTypes.Property: - PropertyInfo pi = (PropertyInfo)mi; + var pi = (PropertyInfo)mi; MethodInfo mm = null; try @@ -317,7 +314,9 @@ private static ClassInfo GetClassInfo(Type type) } if (!(mm.IsPublic || mm.IsFamily || mm.IsFamilyOrAssembly)) + { continue; + } // Check for indexer ParameterInfo[] args = pi.GetIndexParameters(); @@ -338,18 +337,22 @@ private static ClassInfo GetClassInfo(Type type) continue; case MemberTypes.Field: - FieldInfo fi = (FieldInfo)mi; + var fi = (FieldInfo)mi; if (!(fi.IsPublic || fi.IsFamily || fi.IsFamilyOrAssembly)) + { continue; + } ob = new FieldObject(fi); ci.members[mi.Name] = ob; continue; case MemberTypes.Event: - EventInfo ei = (EventInfo)mi; + var ei = (EventInfo)mi; MethodInfo me = ei.GetAddMethod(true); if (!(me.IsPublic || me.IsFamily || me.IsFamilyOrAssembly)) + { continue; + } ob = new EventObject(ei); ci.members[ei.Name] = ob; continue; @@ -358,9 +361,11 @@ private static ClassInfo GetClassInfo(Type type) tp = (Type)mi; if (!(tp.IsNestedPublic || tp.IsNestedFamily || tp.IsNestedFamORAssem)) + { continue; + } // Note the given instance might be uninitialized - ob = ClassManager.GetClass(tp); + ob = GetClass(tp); ci.members[mi.Name] = ob; continue; } @@ -373,9 +378,7 @@ private static ClassInfo GetClassInfo(Type type) name = (string)iter.Key; list = (ArrayList)iter.Value; - MethodInfo[] mlist = (MethodInfo[])list.ToArray( - typeof(MethodInfo) - ); + var mlist = (MethodInfo[])list.ToArray(typeof(MethodInfo)); ob = new MethodObject(type, name, mlist); ci.members[name] = ob; @@ -388,13 +391,13 @@ private static ClassInfo GetClassInfo(Type type) internal class ClassInfo { + public Indexer indexer; + public Hashtable members; + internal ClassInfo(Type t) { members = new Hashtable(); indexer = null; } - - public Hashtable members; - public Indexer indexer; } -} \ No newline at end of file +} diff --git a/src/runtime/classobject.cs b/src/runtime/classobject.cs index bd4702c20..46257c73f 100644 --- a/src/runtime/classobject.cs +++ b/src/runtime/classobject.cs @@ -19,43 +19,42 @@ internal ClassObject(Type tp) : base(tp) ctors = type.GetConstructors(); binder = new ConstructorBinder(type); - for (int i = 0; i < ctors.Length; i++) + foreach (ConstructorInfo t in ctors) { - binder.AddMethod(ctors[i]); + binder.AddMethod(t); } } - //==================================================================== - // Helper to get docstring from reflected constructor info. - //==================================================================== - + /// + /// Helper to get docstring from reflected constructor info. + /// internal IntPtr GetDocString() { MethodBase[] methods = binder.GetMethods(); - string str = ""; - for (int i = 0; i < methods.Length; i++) + var str = ""; + foreach (MethodBase t in methods) { if (str.Length > 0) + { str += Environment.NewLine; - str += methods[i].ToString(); + } + str += t.ToString(); } return Runtime.PyString_FromString(str); } - //==================================================================== - // Implements __new__ for reflected classes and value types. - //==================================================================== - + /// + /// Implements __new__ for reflected classes and value types. + /// public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { - ClassObject self = GetManagedObject(tp) as ClassObject; + var self = GetManagedObject(tp) as ClassObject; // Sanity check: this ensures a graceful error if someone does // something intentially wrong like use the managed metatype for // a class that is not really derived from a managed class. - if (self == null) { return Exceptions.RaiseTypeError("invalid object"); @@ -66,19 +65,16 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) // Primitive types do not have constructors, but they look like // they do from Python. If the ClassObject represents one of the // convertible primitive types, just convert the arg directly. - - if (type.IsPrimitive || type == typeof(String)) + if (type.IsPrimitive || type == typeof(string)) { if (Runtime.PyTuple_Size(args) != 1) { - Exceptions.SetError(Exceptions.TypeError, - "no constructors match given arguments" - ); + Exceptions.SetError(Exceptions.TypeError, "no constructors match given arguments"); return IntPtr.Zero; } IntPtr op = Runtime.PyTuple_GetItem(args, 0); - Object result; + object result; if (!Converter.ToManaged(op, type, out result, true)) { @@ -90,21 +86,17 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) if (type.IsAbstract) { - Exceptions.SetError(Exceptions.TypeError, - "cannot instantiate abstract class" - ); + Exceptions.SetError(Exceptions.TypeError, "cannot instantiate abstract class"); return IntPtr.Zero; } if (type.IsEnum) { - Exceptions.SetError(Exceptions.TypeError, - "cannot instantiate enumeration" - ); + Exceptions.SetError(Exceptions.TypeError, "cannot instantiate enumeration"); return IntPtr.Zero; } - Object obj = self.binder.InvokeRaw(IntPtr.Zero, args, kw); + object obj = self.binder.InvokeRaw(IntPtr.Zero, args, kw); if (obj == null) { return IntPtr.Zero; @@ -114,25 +106,23 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) } - //==================================================================== - // Implementation of [] semantics for reflected types. This exists - // both to implement the Array[int] syntax for creating arrays and - // to support generic name overload resolution using []. - //==================================================================== - + /// + /// Implementation of [] semantics for reflected types. This exists + /// both to implement the Array[int] syntax for creating arrays and + /// to support generic name overload resolution using []. + /// public override IntPtr type_subscript(IntPtr idx) { // If this type is the Array type, the [] means we need to // construct and return an array type of the given element type. - - if ((this.type) == typeof(Array)) + if (type == typeof(Array)) { if (Runtime.PyTuple_Check(idx)) { return Exceptions.RaiseTypeError("type expected"); } - ClassBase c = GetManagedObject(idx) as ClassBase; - Type t = (c != null) ? c.type : Converter.GetTypeByAlias(idx); + var c = GetManagedObject(idx) as ClassBase; + Type t = c != null ? c.type : Converter.GetTypeByAlias(idx); if (t == null) { return Exceptions.RaiseTypeError("type expected"); @@ -146,50 +136,44 @@ public override IntPtr type_subscript(IntPtr idx) // If there are generics in our namespace with the same base name // as the current type, then [] means the caller wants to // bind the generic type matching the given type parameters. - Type[] types = Runtime.PythonArgsToTypeArray(idx); if (types == null) { return Exceptions.RaiseTypeError("type(s) expected"); } - string gname = this.type.FullName + "`" + types.Length.ToString(); - Type gtype = AssemblyManager.LookupType(gname); + Type gtype = AssemblyManager.LookupType($"{type.FullName}`{types.Length}"); if (gtype != null) { - GenericType g = ClassManager.GetClass(gtype) as GenericType; + var g = ClassManager.GetClass(gtype) as GenericType; return g.type_subscript(idx); - /*Runtime.XIncref(g.pyHandle); - return g.pyHandle;*/ + //Runtime.XIncref(g.pyHandle); + //return g.pyHandle; } return Exceptions.RaiseTypeError("unsubscriptable object"); } - //==================================================================== - // Implements __getitem__ for reflected classes and value types. - //==================================================================== - + /// + /// Implements __getitem__ for reflected classes and value types. + /// public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) { //ManagedType self = GetManagedObject(ob); IntPtr tp = Runtime.PyObject_TYPE(ob); - ClassBase cls = (ClassBase)GetManagedObject(tp); + var cls = (ClassBase)GetManagedObject(tp); if (cls.indexer == null || !cls.indexer.CanGet) { - Exceptions.SetError(Exceptions.TypeError, - "unindexable object" - ); + Exceptions.SetError(Exceptions.TypeError, "unindexable object"); return IntPtr.Zero; } // Arg may be a tuple in the case of an indexer with multiple // parameters. If so, use it directly, else make a new tuple // with the index arg (method binders expect arg tuples). - IntPtr args = idx; - bool free = false; + var free = false; if (!Runtime.PyTuple_Check(idx)) { @@ -199,7 +183,7 @@ public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) free = true; } - IntPtr value = IntPtr.Zero; + IntPtr value; try { @@ -216,21 +200,18 @@ public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) } - //==================================================================== - // Implements __setitem__ for reflected classes and value types. - //==================================================================== - + /// + /// Implements __setitem__ for reflected classes and value types. + /// public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) { //ManagedType self = GetManagedObject(ob); IntPtr tp = Runtime.PyObject_TYPE(ob); - ClassBase cls = (ClassBase)GetManagedObject(tp); + var cls = (ClassBase)GetManagedObject(tp); if (cls.indexer == null || !cls.indexer.CanSet) { - Exceptions.SetError(Exceptions.TypeError, - "object doesn't support item assignment" - ); + Exceptions.SetError(Exceptions.TypeError, "object doesn't support item assignment"); return -1; } @@ -238,7 +219,7 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) // parameters. If so, use it directly, else make a new tuple // with the index arg (method binders expect arg tuples). IntPtr args = idx; - bool free = false; + var free = false; if (!Runtime.PyTuple_Check(idx)) { @@ -254,7 +235,7 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) int numOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs); int temp = i + numOfDefaultArgs; IntPtr real = Runtime.PyTuple_New(temp + 1); - for (int n = 0; n < i; n++) + for (var n = 0; n < i; n++) { IntPtr item = Runtime.PyTuple_GetItem(args, n); Runtime.XIncref(item); @@ -262,7 +243,7 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) } // Add Default Args if needed - for (int n = 0; n < numOfDefaultArgs; n++) + for (var n = 0; n < numOfDefaultArgs; n++) { IntPtr item = Runtime.PyTuple_GetItem(defaultArgs, n); Runtime.XIncref(item); @@ -299,36 +280,34 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) } - //==================================================================== - // This is a hack. Generally, no managed class is considered callable - // from Python - with the exception of System.Delegate. It is useful - // to be able to call a System.Delegate instance directly, especially - // when working with multicast delegates. - //==================================================================== - + /// + /// This is a hack. Generally, no managed class is considered callable + /// from Python - with the exception of System.Delegate. It is useful + /// to be able to call a System.Delegate instance directly, especially + /// when working with multicast delegates. + /// public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { //ManagedType self = GetManagedObject(ob); IntPtr tp = Runtime.PyObject_TYPE(ob); - ClassBase cb = (ClassBase)GetManagedObject(tp); + var cb = (ClassBase)GetManagedObject(tp); - if (cb.type != typeof(System.Delegate)) + if (cb.type != typeof(Delegate)) { - Exceptions.SetError(Exceptions.TypeError, - "object is not callable"); + Exceptions.SetError(Exceptions.TypeError, "object is not callable"); return IntPtr.Zero; } - CLRObject co = (CLRObject)ManagedType.GetManagedObject(ob); - Delegate d = co.inst as Delegate; + var co = (CLRObject)GetManagedObject(ob); + var d = co.inst as Delegate; BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; MethodInfo method = d.GetType().GetMethod("Invoke", flags); - MethodBinder binder = new MethodBinder(method); + var binder = new MethodBinder(method); return binder.Invoke(ob, args, kw); } } -} \ No newline at end of file +} diff --git a/src/runtime/clrobject.cs b/src/runtime/clrobject.cs index e7bb345f8..fb3d0e0d7 100644 --- a/src/runtime/clrobject.cs +++ b/src/runtime/clrobject.cs @@ -1,19 +1,17 @@ -using System; -using System.Collections; -using System.Reflection; +using System; using System.Runtime.InteropServices; namespace Python.Runtime { internal class CLRObject : ManagedType { - internal Object inst; + internal object inst; - internal CLRObject(Object ob, IntPtr tp) : base() + internal CLRObject(object ob, IntPtr tp) { IntPtr py = Runtime.PyType_GenericAlloc(tp, 0); - int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags); + long flags = Util.ReadCLong(tp, TypeOffset.tp_flags); if ((flags & TypeFlags.Subclass) != 0) { IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.DictOffset(tp)); @@ -26,9 +24,9 @@ internal CLRObject(Object ob, IntPtr tp) : base() GCHandle gc = GCHandle.Alloc(this); Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (IntPtr)gc); - this.tpHandle = tp; - this.pyHandle = py; - this.gcHandle = gc; + tpHandle = tp; + pyHandle = py; + gcHandle = gc; inst = ob; // Fix the BaseException args (and __cause__ in case of Python 3) @@ -37,27 +35,27 @@ internal CLRObject(Object ob, IntPtr tp) : base() } - internal static CLRObject GetInstance(Object ob, IntPtr pyType) + internal static CLRObject GetInstance(object ob, IntPtr pyType) { return new CLRObject(ob, pyType); } - internal static CLRObject GetInstance(Object ob) + internal static CLRObject GetInstance(object ob) { ClassBase cc = ClassManager.GetClass(ob.GetType()); return GetInstance(ob, cc.tpHandle); } - internal static IntPtr GetInstHandle(Object ob, IntPtr pyType) + internal static IntPtr GetInstHandle(object ob, IntPtr pyType) { CLRObject co = GetInstance(ob, pyType); return co.pyHandle; } - internal static IntPtr GetInstHandle(Object ob, Type type) + internal static IntPtr GetInstHandle(object ob, Type type) { ClassBase cc = ClassManager.GetClass(type); CLRObject co = GetInstance(ob, cc.tpHandle); @@ -65,7 +63,7 @@ internal static IntPtr GetInstHandle(Object ob, Type type) } - internal static IntPtr GetInstHandle(Object ob) + internal static IntPtr GetInstHandle(object ob) { CLRObject co = GetInstance(ob); return co.pyHandle; diff --git a/src/runtime/codegenerator.cs b/src/runtime/codegenerator.cs index 01edd79ba..dc466bafb 100644 --- a/src/runtime/codegenerator.cs +++ b/src/runtime/codegenerator.cs @@ -1,10 +1,7 @@ using System; -using System.Threading; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; -using System.Collections; using System.Reflection; using System.Reflection.Emit; +using System.Threading; namespace Python.Runtime { @@ -16,37 +13,34 @@ namespace Python.Runtime /// internal class CodeGenerator { - AssemblyBuilder aBuilder; - ModuleBuilder mBuilder; + private AssemblyBuilder aBuilder; + private ModuleBuilder mBuilder; internal CodeGenerator() { - AssemblyName aname = new AssemblyName(); - aname.Name = "__CodeGenerator_Assembly"; - AssemblyBuilderAccess aa = AssemblyBuilderAccess.Run; + var aname = new AssemblyName { Name = "__CodeGenerator_Assembly" }; + var aa = AssemblyBuilderAccess.Run; aBuilder = Thread.GetDomain().DefineDynamicAssembly(aname, aa); mBuilder = aBuilder.DefineDynamicModule("__CodeGenerator_Module"); } - //==================================================================== - // DefineType is a shortcut utility to get a new TypeBuilder. - //==================================================================== - + /// + /// DefineType is a shortcut utility to get a new TypeBuilder. + /// internal TypeBuilder DefineType(string name) { - TypeAttributes attrs = TypeAttributes.Public; + var attrs = TypeAttributes.Public; return mBuilder.DefineType(name, attrs); } - //==================================================================== - // DefineType is a shortcut utility to get a new TypeBuilder. - //==================================================================== - + /// + /// DefineType is a shortcut utility to get a new TypeBuilder. + /// internal TypeBuilder DefineType(string name, Type basetype) { - TypeAttributes attrs = TypeAttributes.Public; + var attrs = TypeAttributes.Public; return mBuilder.DefineType(name, attrs, basetype); } } -} \ No newline at end of file +} diff --git a/src/runtime/constructorbinder.cs b/src/runtime/constructorbinder.cs index 7ea7602b8..1fc541920 100644 --- a/src/runtime/constructorbinder.cs +++ b/src/runtime/constructorbinder.cs @@ -3,35 +3,33 @@ namespace Python.Runtime { - //======================================================================== - // A ConstructorBinder encapsulates information about one or more managed - // constructors, and is responsible for selecting the right constructor - // given a set of Python arguments. This is slightly different than the - // standard MethodBinder because of a difference in invoking constructors - // using reflection (which is seems to be a CLR bug). - //======================================================================== - + /// + /// A ConstructorBinder encapsulates information about one or more managed + /// constructors, and is responsible for selecting the right constructor + /// given a set of Python arguments. This is slightly different than the + /// standard MethodBinder because of a difference in invoking constructors + /// using reflection (which is seems to be a CLR bug). + /// internal class ConstructorBinder : MethodBinder { - private Type _containingType = null; + private Type _containingType; - internal ConstructorBinder(Type containingType) : base() + internal ConstructorBinder(Type containingType) { _containingType = containingType; } - //==================================================================== - // Constructors get invoked when an instance of a wrapped managed - // class or a subclass of a managed class is created. This differs - // from the MethodBinder implementation in that we return the raw - // result of the constructor rather than wrapping it as a Python - // object - the reason is that only the caller knows the correct - // Python type to use when wrapping the result (may be a subclass). - //==================================================================== - + /// + /// Constructors get invoked when an instance of a wrapped managed + /// class or a subclass of a managed class is created. This differs + /// from the MethodBinder implementation in that we return the raw + /// result of the constructor rather than wrapping it as a Python + /// object - the reason is that only the caller knows the correct + /// Python type to use when wrapping the result (may be a subclass). + /// internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw) { - return this.InvokeRaw(inst, args, kw, null); + return InvokeRaw(inst, args, kw, null); } /// @@ -49,10 +47,9 @@ internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw) /// Binding binding = this.Bind(inst, args, kw, info); /// to take advantage of Bind()'s ability to use a single MethodBase (CI or MI). /// - internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, - MethodBase info) + internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info) { - Object result; + object result; if (_containingType.IsValueType && !_containingType.IsPrimitive && !_containingType.IsEnum && _containingType != typeof(decimal) && @@ -79,7 +76,7 @@ internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, return result; } - Binding binding = this.Bind(inst, args, kw, info); + Binding binding = Bind(inst, args, kw, info); if (binding == null) { @@ -91,20 +88,18 @@ internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, // any extra args are intended for the subclass' __init__. IntPtr eargs = Runtime.PyTuple_New(0); - binding = this.Bind(inst, eargs, kw); + binding = Bind(inst, eargs, kw); Runtime.XDecref(eargs); if (binding == null) { - Exceptions.SetError(Exceptions.TypeError, - "no constructor matches given arguments" - ); + Exceptions.SetError(Exceptions.TypeError, "no constructor matches given arguments"); return null; } } // Fire the selected ctor and catch errors... - ConstructorInfo ci = (ConstructorInfo)binding.info; + var ci = (ConstructorInfo)binding.info; // Object construction is presumed to be non-blocking and fast // enough that we shouldn't really need to release the GIL. try @@ -123,4 +118,4 @@ internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, return result; } } -} \ No newline at end of file +} diff --git a/src/runtime/constructorbinding.cs b/src/runtime/constructorbinding.cs index 8710f53bf..4839f9913 100644 --- a/src/runtime/constructorbinding.cs +++ b/src/runtime/constructorbinding.cs @@ -9,25 +9,24 @@ namespace Python.Runtime /// /// /// ClassManager stores a ConstructorBinding instance in the class's __dict__['Overloads'] - /// /// SomeType.Overloads[Type, ...] works like this: - /// 1) Python retreives the Overloads attribute from this ClassObject's dictionary normally + /// 1) Python retrieves the Overloads attribute from this ClassObject's dictionary normally /// and finds a non-null tp_descr_get slot which is called by the interpreter /// and returns an IncRef()ed pyHandle to itself. /// 2) The ConstructorBinding object handles the [] syntax in its mp_subscript by matching - /// the Type object parameters to a contructor overload using Type.GetConstructor() - /// [NOTE: I don't know why method overloads are not searched the same way.] - /// and creating the BoundContructor oject which contains ContructorInfo object. + /// the Type object parameters to a constructor overload using Type.GetConstructor() + /// [NOTE: I don't know why method overloads are not searched the same way.] + /// and creating the BoundContructor object which contains ContructorInfo object. /// 3) In tp_call, if ctorInfo is not null, ctorBinder.InvokeRaw() is called. /// internal class ConstructorBinding : ExtensionType { - Type type; // The managed Type being wrapped in a ClassObject - IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create. - ConstructorBinder ctorBinder; - IntPtr repr; + private Type type; // The managed Type being wrapped in a ClassObject + private IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create. + private ConstructorBinder ctorBinder; + private IntPtr repr; - public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder) : base() + public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder) { this.type = type; Runtime.XIncref(pyTypeHndl); @@ -43,12 +42,15 @@ public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBi /// selection. /// /// PyObject* to a Constructors wrapper - /// the instance that the attribute was accessed through, - /// or None when the attribute is accessed through the owner + /// + /// the instance that the attribute was accessed through, + /// or None when the attribute is accessed through the owner + /// /// always the owner class - /// a CtorMapper (that borrows a reference to this python type and the - /// ClassObject's ConstructorBinder) wrapper. - /// + /// + /// a CtorMapper (that borrows a reference to this python type and the + /// ClassObject's ConstructorBinder) wrapper. + /// /// /// Python 2.6.5 docs: /// object.__get__(self, instance, owner) @@ -60,7 +62,7 @@ public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBi /// public static IntPtr tp_descr_get(IntPtr op, IntPtr instance, IntPtr owner) { - ConstructorBinding self = (ConstructorBinding)GetManagedObject(op); + var self = (ConstructorBinding)GetManagedObject(op); if (self == null) { return IntPtr.Zero; @@ -77,20 +79,17 @@ public static IntPtr tp_descr_get(IntPtr op, IntPtr instance, IntPtr owner) return self.pyHandle; } - //==================================================================== - // Implement explicit overload selection using subscript syntax ([]). - //==================================================================== /// + /// Implement explicit overload selection using subscript syntax ([]). + /// + /// /// ConstructorBinding.GetItem(PyObject *o, PyObject *key) /// Return element of o corresponding to the object key or NULL on failure. /// This is the equivalent of the Python expression o[key]. - /// - /// - /// - /// + /// public static IntPtr mp_subscript(IntPtr op, IntPtr key) { - ConstructorBinding self = (ConstructorBinding)GetManagedObject(op); + var self = (ConstructorBinding)GetManagedObject(op); Type[] types = Runtime.PythonArgsToTypeArray(key); if (types == null) @@ -102,23 +101,21 @@ public static IntPtr mp_subscript(IntPtr op, IntPtr key) ConstructorInfo ci = self.type.GetConstructor(types); if (ci == null) { - string msg = "No match found for constructor signature"; - return Exceptions.RaiseTypeError(msg); + return Exceptions.RaiseTypeError("No match found for constructor signature"); } - BoundContructor boundCtor = new BoundContructor(self.type, self.pyTypeHndl, self.ctorBinder, ci); + var boundCtor = new BoundContructor(self.type, self.pyTypeHndl, self.ctorBinder, ci); - /* Since nothing's chached, do we need the increment??? + /* Since nothing is cached, do we need the increment??? Runtime.XIncref(boundCtor.pyHandle); // Decref'd by the interpreter??? */ return boundCtor.pyHandle; } - //==================================================================== - // ConstructorBinding __repr__ implementation [borrowed from MethodObject]. - //==================================================================== - + /// + /// ConstructorBinding __repr__ implementation [borrowed from MethodObject]. + /// public static IntPtr tp_repr(IntPtr ob) { - ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob); + var self = (ConstructorBinding)GetManagedObject(ob); if (self.repr != IntPtr.Zero) { Runtime.XIncref(self.repr); @@ -126,27 +123,28 @@ public static IntPtr tp_repr(IntPtr ob) } MethodBase[] methods = self.ctorBinder.GetMethods(); string name = self.type.FullName; - string doc = ""; - for (int i = 0; i < methods.Length; i++) + var doc = ""; + foreach (MethodBase t in methods) { if (doc.Length > 0) + { doc += "\n"; - string str = methods[i].ToString(); + } + string str = t.ToString(); int idx = str.IndexOf("("); - doc += String.Format("{0}{1}", name, str.Substring(idx)); + doc += string.Format("{0}{1}", name, str.Substring(idx)); } self.repr = Runtime.PyString_FromString(doc); Runtime.XIncref(self.repr); return self.repr; } - //==================================================================== - // ConstructorBinding dealloc implementation. - //==================================================================== - - public static new void tp_dealloc(IntPtr ob) + /// + /// ConstructorBinding dealloc implementation. + /// + public new static void tp_dealloc(IntPtr ob) { - ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob); + var self = (ConstructorBinding)GetManagedObject(ob); Runtime.XDecref(self.repr); Runtime.XDecref(self.pyTypeHndl); ExtensionType.FinalizeObject(self); @@ -154,7 +152,7 @@ public static IntPtr tp_repr(IntPtr ob) } /// - /// Implements a Python type that constucts the given Type given a particular ContructorInfo. + /// Implements a Python type that constructs the given Type given a particular ContructorInfo. /// /// /// Here mostly because I wanted a new __repr__ function for the selected constructor. @@ -163,14 +161,13 @@ public static IntPtr tp_repr(IntPtr ob) /// internal class BoundContructor : ExtensionType { - Type type; // The managed Type being wrapped in a ClassObject - IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create. - ConstructorBinder ctorBinder; - ConstructorInfo ctorInfo; - IntPtr repr; + private Type type; // The managed Type being wrapped in a ClassObject + private IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create. + private ConstructorBinder ctorBinder; + private ConstructorInfo ctorInfo; + private IntPtr repr; public BoundContructor(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder, ConstructorInfo ci) - : base() { this.type = type; Runtime.XIncref(pyTypeHndl); @@ -183,13 +180,13 @@ public BoundContructor(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinde /// /// BoundContructor.__call__(PyObject *callable_object, PyObject *args, PyObject *kw) /// - /// PyObject *callable_object + /// PyObject *callable_object /// PyObject *args /// PyObject *kw /// A reference to a new instance of the class by invoking the selected ctor(). public static IntPtr tp_call(IntPtr op, IntPtr args, IntPtr kw) { - BoundContructor self = (BoundContructor)GetManagedObject(op); + var self = (BoundContructor)GetManagedObject(op); // Even though a call with null ctorInfo just produces the old behavior /*if (self.ctorInfo == null) { string msg = "Usage: Class.Overloads[CLR_or_python_Type, ...]"; @@ -197,7 +194,7 @@ public static IntPtr tp_call(IntPtr op, IntPtr args, IntPtr kw) }*/ // Bind using ConstructorBinder.Bind and invoke the ctor providing a null instancePtr // which will fire self.ctorInfo using ConstructorInfo.Invoke(). - Object obj = self.ctorBinder.InvokeRaw(IntPtr.Zero, args, kw, self.ctorInfo); + object obj = self.ctorBinder.InvokeRaw(IntPtr.Zero, args, kw, self.ctorInfo); if (obj == null) { // XXX set an error @@ -208,13 +205,12 @@ public static IntPtr tp_call(IntPtr op, IntPtr args, IntPtr kw) return CLRObject.GetInstHandle(obj, self.pyTypeHndl); } - //==================================================================== - // BoundContructor __repr__ implementation [borrowed from MethodObject]. - //==================================================================== - + /// + /// BoundContructor __repr__ implementation [borrowed from MethodObject]. + /// public static IntPtr tp_repr(IntPtr ob) { - BoundContructor self = (BoundContructor)GetManagedObject(ob); + var self = (BoundContructor)GetManagedObject(ob); if (self.repr != IntPtr.Zero) { Runtime.XIncref(self.repr); @@ -223,22 +219,21 @@ public static IntPtr tp_repr(IntPtr ob) string name = self.type.FullName; string str = self.ctorInfo.ToString(); int idx = str.IndexOf("("); - str = String.Format("returns a new {0}{1}", name, str.Substring(idx)); + str = string.Format("returns a new {0}{1}", name, str.Substring(idx)); self.repr = Runtime.PyString_FromString(str); Runtime.XIncref(self.repr); return self.repr; } - //==================================================================== - // ConstructorBinding dealloc implementation. - //==================================================================== - - public static new void tp_dealloc(IntPtr ob) + /// + /// ConstructorBinding dealloc implementation. + /// + public new static void tp_dealloc(IntPtr ob) { - BoundContructor self = (BoundContructor)GetManagedObject(ob); + var self = (BoundContructor)GetManagedObject(ob); Runtime.XDecref(self.repr); Runtime.XDecref(self.pyTypeHndl); - ExtensionType.FinalizeObject(self); + FinalizeObject(self); } } } diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs index ac1085c18..13498e3dc 100644 --- a/src/runtime/converter.cs +++ b/src/runtime/converter.cs @@ -1,35 +1,35 @@ using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; using System.Reflection; using System.Runtime.InteropServices; -using System.Globalization; using System.Security; -using System.Collections; namespace Python.Runtime { - //======================================================================== - // Performs data conversions between managed types and Python types. - //======================================================================== - - [SuppressUnmanagedCodeSecurityAttribute()] + /// + /// Performs data conversions between managed types and Python types. + /// + [SuppressUnmanagedCodeSecurity] internal class Converter { private Converter() { } - static NumberFormatInfo nfi; - static Type objectType; - static Type stringType; - static Type singleType; - static Type doubleType; - static Type decimalType; - static Type int16Type; - static Type int32Type; - static Type int64Type; - static Type flagsType; - static Type boolType; - static Type typeType; + private static NumberFormatInfo nfi; + private static Type objectType; + private static Type stringType; + private static Type singleType; + private static Type doubleType; + private static Type decimalType; + private static Type int16Type; + private static Type int32Type; + private static Type int64Type; + private static Type flagsType; + private static Type boolType; + private static Type typeType; static Converter() { @@ -48,85 +48,76 @@ static Converter() } - //==================================================================== - // Given a builtin Python type, return the corresponding CLR type. - //==================================================================== - + /// + /// Given a builtin Python type, return the corresponding CLR type. + /// internal static Type GetTypeByAlias(IntPtr op) { - if ((op == Runtime.PyStringType) || - (op == Runtime.PyUnicodeType)) - { + if (op == Runtime.PyStringType) return stringType; - } - else if (op == Runtime.PyIntType) - { + + if (op == Runtime.PyUnicodeType) + return stringType; + + if (op == Runtime.PyIntType) return int32Type; - } - else if (op == Runtime.PyLongType) - { + + if (op == Runtime.PyLongType) return int64Type; - } - else if (op == Runtime.PyFloatType) - { + + if (op == Runtime.PyFloatType) return doubleType; - } - else if (op == Runtime.PyBoolType) - { + + if (op == Runtime.PyBoolType) return boolType; - } + return null; } internal static IntPtr GetPythonTypeByAlias(Type op) { if (op == stringType) - { return Runtime.PyUnicodeType; - } -#if PYTHON3 - else if ((op == int16Type) || - (op == int32Type) || - (op == int64Type)) { + + if (op == int16Type) return Runtime.PyIntType; - } -#endif - else if ((op == int16Type) || - (op == int32Type)) - { + + if (op == int32Type) return Runtime.PyIntType; - } - else if (op == int64Type) - { + + if (op == int64Type && Runtime.IsPython2) return Runtime.PyLongType; - } - else if ((op == doubleType) || - (op == singleType)) - { + + if (op == int64Type) + return Runtime.PyIntType; + + if (op == doubleType) return Runtime.PyFloatType; - } - else if (op == boolType) - { + + if (op == singleType) + return Runtime.PyFloatType; + + if (op == boolType) return Runtime.PyBoolType; - } + return IntPtr.Zero; } - //==================================================================== - // Return a Python object for the given native object, converting - // basic types (string, int, etc.) into equivalent Python objects. - // This always returns a new reference. Note that the System.Decimal - // type has no Python equivalent and converts to a managed instance. - //==================================================================== + /// + /// Return a Python object for the given native object, converting + /// basic types (string, int, etc.) into equivalent Python objects. + /// This always returns a new reference. Note that the System.Decimal + /// type has no Python equivalent and converts to a managed instance. + /// internal static IntPtr ToPython(T value) { return ToPython(value, typeof(T)); } - internal static IntPtr ToPython(Object value, Type type) + internal static IntPtr ToPython(object value, Type type) { - if(value is PyObject) + if (value is PyObject) { IntPtr handle = ((PyObject)value).Handle; Runtime.XIncref(handle); @@ -143,12 +134,36 @@ internal static IntPtr ToPython(Object value, Type type) return result; } + if (value is IList && value.GetType().IsGenericType) + { + using (var resultlist = new PyList()) + { + foreach (object o in (IEnumerable)value) + { + using (var p = new PyObject(ToPython(o, o?.GetType()))) + { + resultlist.Append(p); + } + } + Runtime.XIncref(resultlist.Handle); + return resultlist.Handle; + } + } + // it the type is a python subclass of a managed type then return the - // underying python object rather than construct a new wrapper object. - IPythonDerivedType pyderived = value as IPythonDerivedType; + // underlying python object rather than construct a new wrapper object. + var pyderived = value as IPythonDerivedType; if (null != pyderived) { + #if NETSTANDARD return ClassDerivedObject.ToPython(pyderived); + #else + // if object is remote don't do this + if (!System.Runtime.Remoting.RemotingServices.IsTransparentProxy(pyderived)) + { + return ClassDerivedObject.ToPython(pyderived); + } + #endif } // hmm - from Python, we almost never care what the declared @@ -222,7 +237,9 @@ internal static IntPtr ToPython(Object value, Type type) foreach (object o in (IEnumerable)value) { using (var p = new PyObject(ToPython(o, o?.GetType()))) + { resultlist.Append(p); + } } Runtime.XIncref(resultlist.Handle); return resultlist.Handle; @@ -234,12 +251,11 @@ internal static IntPtr ToPython(Object value, Type type) } - //==================================================================== - // In a few situations, we don't have any advisory type information - // when we want to convert an object to Python. - //==================================================================== - - internal static IntPtr ToPythonImplicit(Object value) + /// + /// In a few situations, we don't have any advisory type information + /// when we want to convert an object to Python. + /// + internal static IntPtr ToPythonImplicit(object value) { if (value == null) { @@ -252,11 +268,10 @@ internal static IntPtr ToPythonImplicit(Object value) } - //==================================================================== - // Return a managed object for the given Python object, taking funny - // byref types into account. - //==================================================================== - + /// + /// Return a managed object for the given Python object, taking funny + /// byref types into account. + /// internal static bool ToManaged(IntPtr value, Type type, out object result, bool setError) { @@ -269,7 +284,7 @@ internal static bool ToManaged(IntPtr value, Type type, internal static bool ToManagedValue(IntPtr value, Type obType, - out Object result, bool setError) + out object result, bool setError) { if (obType == typeof(PyObject)) { @@ -293,9 +308,7 @@ internal static bool ToManagedValue(IntPtr value, Type obType, result = tmp; return true; } - string err = "value cannot be converted to {0}"; - err = String.Format(err, obType); - Exceptions.SetError(Exceptions.TypeError, err); + Exceptions.SetError(Exceptions.TypeError, $"value cannot be converted to {obType}"); return false; } if (mt is ClassBase) @@ -303,7 +316,7 @@ internal static bool ToManagedValue(IntPtr value, Type obType, result = ((ClassBase)mt).type; return true; } - // shouldnt happen + // shouldn't happen return false; } @@ -313,6 +326,17 @@ internal static bool ToManagedValue(IntPtr value, Type obType, return true; } + if (obType.IsGenericType && obType.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + if( value == Runtime.PyNone ) + { + result = null; + return true; + } + // Set type to underlying type + obType = obType.GetGenericArguments()[0]; + } + if (obType.IsArray) { return ToArray(value, obType, out result, setError); @@ -323,57 +347,49 @@ internal static bool ToManagedValue(IntPtr value, Type obType, return ToEnum(value, obType, out result, setError); } - // Conversion to 'Object' is done based on some reasonable - // default conversions (Python string -> managed string, - // Python int -> Int32 etc.). - + // Conversion to 'Object' is done based on some reasonable default + // conversions (Python string -> managed string, Python int -> Int32 etc.). if (obType == objectType) { if (Runtime.IsStringType(value)) { - return ToPrimitive(value, stringType, out result, - setError); + return ToPrimitive(value, stringType, out result, setError); } - else if (Runtime.PyBool_Check(value)) + if (Runtime.PyBool_Check(value)) { return ToPrimitive(value, boolType, out result, setError); } - else if (Runtime.PyInt_Check(value)) + if (Runtime.PyInt_Check(value)) { return ToPrimitive(value, int32Type, out result, setError); } - else if (Runtime.PyLong_Check(value)) + if (Runtime.PyLong_Check(value)) { return ToPrimitive(value, int64Type, out result, setError); } - else if (Runtime.PyFloat_Check(value)) + if (Runtime.PyFloat_Check(value)) { return ToPrimitive(value, doubleType, out result, setError); } - else if (Runtime.PySequence_Check(value)) + if (Runtime.PySequence_Check(value)) { - return ToArray(value, typeof(object[]), out result, - setError); + return ToArray(value, typeof(object[]), out result, setError); } if (setError) { - Exceptions.SetError(Exceptions.TypeError, - "value cannot be converted to Object" - ); + Exceptions.SetError(Exceptions.TypeError, "value cannot be converted to Object"); } return false; } - // Conversion to 'Type' is done using the same mappings as above - // for objects. - + // Conversion to 'Type' is done using the same mappings as above for objects. if (obType == typeType) { if (value == Runtime.PyStringType) @@ -382,31 +398,31 @@ internal static bool ToManagedValue(IntPtr value, Type obType, return true; } - else if (value == Runtime.PyBoolType) + if (value == Runtime.PyBoolType) { result = boolType; return true; } - else if (value == Runtime.PyIntType) + if (value == Runtime.PyIntType) { result = int32Type; return true; } - else if (value == Runtime.PyLongType) + if (value == Runtime.PyLongType) { result = int64Type; return true; } - else if (value == Runtime.PyFloatType) + if (value == Runtime.PyFloatType) { result = doubleType; return true; } - else if (value == Runtime.PyListType || value == Runtime.PyTupleType) + if (value == Runtime.PyListType || value == Runtime.PyTupleType) { result = typeof(object[]); return true; @@ -414,9 +430,7 @@ internal static bool ToManagedValue(IntPtr value, Type obType, if (setError) { - Exceptions.SetError(Exceptions.TypeError, - "value cannot be converted to Type" - ); + Exceptions.SetError(Exceptions.TypeError, "value cannot be converted to Type"); } return false; @@ -425,12 +439,10 @@ internal static bool ToManagedValue(IntPtr value, Type obType, return ToPrimitive(value, obType, out result, setError); } - //==================================================================== - // Convert a Python value to an instance of a primitive managed type. - //==================================================================== - - static bool ToPrimitive(IntPtr value, Type obType, out Object result, - bool setError) + /// + /// Convert a Python value to an instance of a primitive managed type. + /// + private static bool ToPrimitive(IntPtr value, Type obType, out object result, bool setError) { IntPtr overflow = Exceptions.OverflowError; TypeCode tc = Type.GetTypeCode(obType); @@ -450,9 +462,8 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result, return true; case TypeCode.Int32: -#if PYTHON2 // Trickery to support 64-bit platforms. - if (IntPtr.Size == 4) + if (Runtime.IsPython2 && Runtime.Is32Bit) { op = Runtime.PyNumber_Int(value); @@ -476,12 +487,8 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result, result = ival; return true; } - else + else // Python3 always use PyLong API { -#elif PYTHON3 - // When using Python3 always use the PyLong API - { -#endif op = Runtime.PyNumber_Long(value); if (op == IntPtr.Zero) { @@ -494,7 +501,7 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result, } long ll = (long)Runtime.PyLong_AsLongLong(op); Runtime.XDecref(op); - if ((ll == -1) && Exceptions.ErrorOccurred()) + if (ll == -1 && Exceptions.ErrorOccurred()) { goto overflow; } @@ -507,27 +514,27 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result, } case TypeCode.Boolean: - result = (Runtime.PyObject_IsTrue(value) != 0); + result = Runtime.PyObject_IsTrue(value) != 0; return true; case TypeCode.Byte: #if PYTHON3 - if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) - { - if (Runtime.PyBytes_Size(value) == 1) + if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { - op = Runtime.PyBytes_AS_STRING(value); - result = (byte)Marshal.ReadByte(op); - return true; + if (Runtime.PyBytes_Size(value) == 1) + { + op = Runtime.PyBytes_AS_STRING(value); + result = (byte)Marshal.ReadByte(op); + return true; + } + goto type_error; } - goto type_error; - } #elif PYTHON2 if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { if (Runtime.PyString_Size(value) == 1) { - op = Runtime.PyString_AS_STRING(value); + op = Runtime.PyString_AsString(value); result = (byte)Marshal.ReadByte(op); return true; } @@ -557,20 +564,22 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result, case TypeCode.SByte: #if PYTHON3 - if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { - if (Runtime.PyBytes_Size(value) == 1) { - op = Runtime.PyBytes_AS_STRING(value); - result = (byte)Marshal.ReadByte(op); - return true; + if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) + { + if (Runtime.PyBytes_Size(value) == 1) + { + op = Runtime.PyBytes_AS_STRING(value); + result = (byte)Marshal.ReadByte(op); + return true; + } + goto type_error; } - goto type_error; - } #elif PYTHON2 if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { if (Runtime.PyString_Size(value) == 1) { - op = Runtime.PyString_AS_STRING(value); + op = Runtime.PyString_AsString(value); result = (sbyte)Marshal.ReadByte(op); return true; } @@ -600,43 +609,36 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result, case TypeCode.Char: #if PYTHON3 - if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { - if (Runtime.PyBytes_Size(value) == 1) { - op = Runtime.PyBytes_AS_STRING(value); - result = (byte)Marshal.ReadByte(op); - return true; + if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) + { + if (Runtime.PyBytes_Size(value) == 1) + { + op = Runtime.PyBytes_AS_STRING(value); + result = (byte)Marshal.ReadByte(op); + return true; + } + goto type_error; } - goto type_error; - } #elif PYTHON2 if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { if (Runtime.PyString_Size(value) == 1) { - op = Runtime.PyString_AS_STRING(value); + op = Runtime.PyString_AsString(value); result = (char)Marshal.ReadByte(op); return true; } goto type_error; } #endif - else if (Runtime.PyObject_TypeCheck(value, - Runtime.PyUnicodeType)) + else if (Runtime.PyObject_TypeCheck(value, Runtime.PyUnicodeType)) { if (Runtime.PyUnicode_GetSize(value) == 1) { - op = Runtime.PyUnicode_AS_UNICODE(value); -#if !UCS4 - // 2011-01-02: Marshal as character array because the cast - // result = (char)Marshal.ReadInt16(op); throws an OverflowException - // on negative numbers with Check Overflow option set on the project - Char[] buff = new Char[1]; - Marshal.Copy(op, buff, 0, 1); - result = buff[0]; -#else - // XXX this is probably NOT correct? - result = (char)Marshal.ReadInt32(op); -#endif + op = Runtime.PyUnicode_AsUnicode(value); + Char[] buff = new Char[1]; + Marshal.Copy(op, buff, 0, 1); + result = buff[0]; return true; } goto type_error; @@ -776,10 +778,14 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result, goto type_error; } double dd = Runtime.PyFloat_AsDouble(op); + Runtime.CheckExceptionOccurred(); Runtime.XDecref(op); if (dd > Single.MaxValue || dd < Single.MinValue) { - goto overflow; + if (!double.IsInfinity(dd)) + { + goto overflow; + } } result = (float)dd; return true; @@ -791,11 +797,8 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result, goto type_error; } double d = Runtime.PyFloat_AsDouble(op); + Runtime.CheckExceptionOccurred(); Runtime.XDecref(op); - if (d > Double.MaxValue || d < Double.MinValue) - { - goto overflow; - } result = d; return true; } @@ -805,10 +808,8 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result, if (setError) { - string format = "'{0}' value cannot be converted to {1}"; string tpName = Runtime.PyObject_GetTypeName(value); - string error = String.Format(format, tpName, obType); - Exceptions.SetError(Exceptions.TypeError, error); + Exceptions.SetError(Exceptions.TypeError, $"'{tpName}' value cannot be converted to {obType}"); } return false; @@ -817,34 +818,28 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result, if (setError) { - string error = "value too large to convert"; - Exceptions.SetError(Exceptions.OverflowError, error); + Exceptions.SetError(Exceptions.OverflowError, "value too large to convert"); } return false; } - static void SetConversionError(IntPtr value, Type target) + private static void SetConversionError(IntPtr value, Type target) { IntPtr ob = Runtime.PyObject_Repr(value); string src = Runtime.GetManagedString(ob); Runtime.XDecref(ob); - string error = String.Format( - "Cannot convert {0} to {1}", src, target - ); - Exceptions.SetError(Exceptions.TypeError, error); + Exceptions.SetError(Exceptions.TypeError, $"Cannot convert {src} to {target}"); } - //==================================================================== - // Convert a Python value to a correctly typed managed array instance. - // The Python value must support the Python sequence protocol and the - // items in the sequence must be convertible to the target array type. - //==================================================================== - - static bool ToArray(IntPtr value, Type obType, out Object result, - bool setError) + /// + /// Convert a Python value to a correctly typed managed array instance. + /// The Python value must support the Python sequence protocol and the + /// items in the sequence must be convertible to the target array type. + /// + private static bool ToArray(IntPtr value, Type obType, out object result, bool setError) { Type elementType = obType.GetElementType(); int size = Runtime.PySequence_Size(value); @@ -861,11 +856,10 @@ static bool ToArray(IntPtr value, Type obType, out Object result, Array items = Array.CreateInstance(elementType, size); - // XXX - is there a better way to unwrap this if it is a real - // array? - for (int i = 0; i < size; i++) + // XXX - is there a better way to unwrap this if it is a real array? + for (var i = 0; i < size; i++) { - Object obj = null; + object obj = null; IntPtr item = Runtime.PySequence_GetItem(value, i); if (item == IntPtr.Zero) { @@ -891,12 +885,10 @@ static bool ToArray(IntPtr value, Type obType, out Object result, } - //==================================================================== - // Convert a Python value to a correctly typed managed enum instance. - //==================================================================== - - static bool ToEnum(IntPtr value, Type obType, out Object result, - bool setError) + /// + /// Convert a Python value to a correctly typed managed enum instance. + /// + private static bool ToEnum(IntPtr value, Type obType, out object result, bool setError) { Type etype = Enum.GetUnderlyingType(obType); result = null; @@ -920,8 +912,7 @@ static bool ToEnum(IntPtr value, Type obType, out Object result, if (setError) { - string error = "invalid enumeration value"; - Exceptions.SetError(Exceptions.ValueError, error); + Exceptions.SetError(Exceptions.ValueError, "invalid enumeration value"); } return false; diff --git a/src/runtime/debughelper.cs b/src/runtime/debughelper.cs index d65300e39..2a91a74b4 100644 --- a/src/runtime/debughelper.cs +++ b/src/runtime/debughelper.cs @@ -1,8 +1,7 @@ using System; -using System.Collections; +using System.Diagnostics; using System.Reflection; using System.Runtime.InteropServices; -using System.Diagnostics; using System.Threading; namespace Python.Runtime @@ -10,7 +9,7 @@ namespace Python.Runtime /// /// Debugging helper utilities. /// The methods are only executed when the DEBUG flag is set. Otherwise - /// they are automagically hidden by the compiler and silently surpressed. + /// they are automagically hidden by the compiler and silently suppressed. /// internal class DebugUtil { @@ -20,19 +19,18 @@ public static void Print(string msg, params IntPtr[] args) string result = msg; result += " "; - for (int i = 0; i < args.Length; i++) + foreach (IntPtr t in args) { - if (args[i] == IntPtr.Zero) + if (t == IntPtr.Zero) { Console.WriteLine("null arg to print"); } - IntPtr ob = Runtime.PyObject_Repr(args[i]); + IntPtr ob = Runtime.PyObject_Repr(t); result += Runtime.GetManagedString(ob); Runtime.XDecref(ob); result += " "; } Console.WriteLine(result); - return; } [Conditional("DEBUG")] @@ -50,13 +48,13 @@ internal static void DumpType(IntPtr type) Console.WriteLine("Dump type: {0}", name); op = Marshal.ReadIntPtr(type, TypeOffset.ob_type); - DebugUtil.Print(" type: ", op); + Print(" type: ", op); op = Marshal.ReadIntPtr(type, TypeOffset.tp_base); - DebugUtil.Print(" base: ", op); + Print(" base: ", op); op = Marshal.ReadIntPtr(type, TypeOffset.tp_bases); - DebugUtil.Print(" bases: ", op); + Print(" bases: ", op); //op = Marshal.ReadIntPtr(type, TypeOffset.tp_mro); //DebugUtil.Print(" mro: ", op); @@ -65,9 +63,9 @@ internal static void DumpType(IntPtr type) FieldInfo[] slots = typeof(TypeOffset).GetFields(); int size = IntPtr.Size; - for (int i = 0; i < slots.Length; i++) + for (var i = 0; i < slots.Length; i++) { - int offset = i*size; + int offset = i * size; name = slots[i].Name; op = Marshal.ReadIntPtr(type, offset); Console.WriteLine(" {0}: {1}", name, op); @@ -83,7 +81,7 @@ internal static void DumpType(IntPtr type) } else { - DebugUtil.Print(" dict: ", op); + Print(" dict: ", op); } } @@ -91,11 +89,11 @@ internal static void DumpType(IntPtr type) internal static void DumpInst(IntPtr ob) { IntPtr tp = Runtime.PyObject_TYPE(ob); - int sz = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_basicsize); + var sz = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_basicsize); - for (int i = 0; i < sz; i += IntPtr.Size) + for (var i = 0; i < sz; i += IntPtr.Size) { - IntPtr pp = new IntPtr(ob.ToInt64() + i); + var pp = new IntPtr(ob.ToInt64() + i); IntPtr v = Marshal.ReadIntPtr(pp); Console.WriteLine("offset {0}: {1}", i, v); } @@ -107,7 +105,7 @@ internal static void DumpInst(IntPtr ob) [Conditional("DEBUG")] internal static void debug(string msg) { - StackTrace st = new StackTrace(1, true); + var st = new StackTrace(1, true); StackFrame sf = st.GetFrame(0); MethodBase mb = sf.GetMethod(); Type mt = mb.DeclaringType; @@ -116,7 +114,28 @@ internal static void debug(string msg) string tid = t.GetHashCode().ToString(); Console.WriteLine("thread {0} : {1}", tid, caller); Console.WriteLine(" {0}", msg); - return; + } + + /// + /// Helper function to inspect/compare managed to native conversions. + /// Especially useful when debugging CustomMarshaler. + /// + /// + [Conditional("DEBUG")] + public static void PrintHexBytes(byte[] bytes) + { + if ((bytes == null) || (bytes.Length == 0)) + { + Console.WriteLine(""); + } + else + { + foreach (byte t in bytes) + { + Console.Write("{0:X2} ", t); + } + Console.WriteLine(); + } } } -} \ No newline at end of file +} diff --git a/src/runtime/delegatemanager.cs b/src/runtime/delegatemanager.cs index 1e652214b..7632816d1 100644 --- a/src/runtime/delegatemanager.cs +++ b/src/runtime/delegatemanager.cs @@ -1,7 +1,4 @@ using System; -using System.Threading; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; using System.Collections; using System.Reflection; using System.Reflection.Emit; @@ -14,13 +11,13 @@ namespace Python.Runtime /// internal class DelegateManager { - Hashtable cache; - Type basetype; - Type listtype; - Type voidtype; - Type typetype; - Type ptrtype; - CodeGenerator codeGenerator; + private Hashtable cache; + private Type basetype; + private Type listtype; + private Type voidtype; + private Type typetype; + private Type ptrtype; + private CodeGenerator codeGenerator; public DelegateManager() { @@ -33,27 +30,25 @@ public DelegateManager() codeGenerator = new CodeGenerator(); } - //==================================================================== - // Given a true delegate instance, return the PyObject handle of the - // Python object implementing the delegate (or IntPtr.Zero if the - // delegate is not implemented in Python code. - //==================================================================== - + /// + /// Given a true delegate instance, return the PyObject handle of the + /// Python object implementing the delegate (or IntPtr.Zero if the + /// delegate is not implemented in Python code. + /// public IntPtr GetPythonHandle(Delegate d) { - if ((d != null) && (d.Target is Dispatcher)) + if (d?.Target is Dispatcher) { - Dispatcher disp = d.Target as Dispatcher; + var disp = (Dispatcher)d.Target; return disp.target; } return IntPtr.Zero; } - //==================================================================== - // GetDispatcher is responsible for creating a class that provides - // an appropriate managed callback method for a given delegate type. - //==================================================================== - + /// + /// GetDispatcher is responsible for creating a class that provides + /// an appropriate managed callback method for a given delegate type. + /// private Type GetDispatcher(Type dtype) { // If a dispatcher type for the given delegate type has already @@ -63,25 +58,24 @@ private Type GetDispatcher(Type dtype) // unique signatures rather than delegate types, since multiple // delegate types with the same sig could use the same dispatcher. - Object item = cache[dtype]; + object item = cache[dtype]; if (item != null) { return (Type)item; } - string name = "__" + dtype.FullName + "Dispatcher"; + string name = $"__{dtype.FullName}Dispatcher"; name = name.Replace('.', '_'); name = name.Replace('+', '_'); TypeBuilder tb = codeGenerator.DefineType(name, basetype); // Generate a constructor for the generated type that calls the // appropriate constructor of the Dispatcher base type. - MethodAttributes ma = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; - CallingConventions cc = CallingConventions.Standard; + var cc = CallingConventions.Standard; Type[] args = { ptrtype, typetype }; ConstructorBuilder cb = tb.DefineConstructor(ma, cc, args); ConstructorInfo ci = basetype.GetConstructor(args); @@ -98,22 +92,16 @@ private Type GetDispatcher(Type dtype) // arguments and hands them to the Dispatch() method, which deals // with converting the arguments, calling the Python method and // converting the result of the call. - MethodInfo method = dtype.GetMethod("Invoke"); ParameterInfo[] pi = method.GetParameters(); - Type[] signature = new Type[pi.Length]; - for (int i = 0; i < pi.Length; i++) + var signature = new Type[pi.Length]; + for (var i = 0; i < pi.Length; i++) { signature[i] = pi[i].ParameterType; } - MethodBuilder mb = tb.DefineMethod( - "Invoke", - MethodAttributes.Public, - method.ReturnType, - signature - ); + MethodBuilder mb = tb.DefineMethod("Invoke", MethodAttributes.Public, method.ReturnType, signature); ConstructorInfo ctor = listtype.GetConstructor(Type.EmptyTypes); MethodInfo dispatch = basetype.GetMethod("Dispatch"); @@ -124,7 +112,7 @@ private Type GetDispatcher(Type dtype) il.Emit(OpCodes.Newobj, ctor); il.Emit(OpCodes.Stloc_0); - for (int c = 0; c < signature.Length; c++) + for (var c = 0; c < signature.Length; c++) { Type t = signature[c]; il.Emit(OpCodes.Ldloc_0); @@ -159,12 +147,11 @@ private Type GetDispatcher(Type dtype) return disp; } - //==================================================================== - // Given a delegate type and a callable Python object, GetDelegate - // returns an instance of the delegate type. The delegate instance - // returned will dispatch calls to the given Python object. - //==================================================================== - + /// + /// Given a delegate type and a callable Python object, GetDelegate + /// returns an instance of the delegate type. The delegate instance + /// returned will dispatch calls to the given Python object. + /// internal Delegate GetDelegate(Type dtype, IntPtr callable) { Type dispatcher = GetDispatcher(dtype); @@ -192,9 +179,7 @@ A possible alternate strategy would be to create custom subclasses of the required delegate type, storing the IntPtr in it directly. This would be slightly cleaner, but I'm not sure if delegates are too "special" for this to work. It would be more work, so for now - the 80/20 rule applies :) - - */ + the 80/20 rule applies :) */ public class Dispatcher { @@ -210,6 +195,10 @@ public Dispatcher(IntPtr target, Type dtype) ~Dispatcher() { + // We needs to disable Finalizers until it's valid implementation. + // Current implementation can produce low probability floating bugs. + return; + // Note: the managed GC thread can run and try to free one of // these *after* the Python runtime has been finalized! if (Runtime.Py_IsInitialized() > 0) @@ -246,7 +235,7 @@ public object TrueDispatch(ArrayList args) IntPtr pyargs = Runtime.PyTuple_New(pi.Length); Type rtype = method.ReturnType; - for (int i = 0; i < pi.Length; i++) + for (var i = 0; i < pi.Length; i++) { // Here we own the reference to the Python value, and we // give the ownership to the arg tuple. @@ -259,7 +248,7 @@ public object TrueDispatch(ArrayList args) if (op == IntPtr.Zero) { - PythonException e = new PythonException(); + var e = new PythonException(); throw e; } @@ -268,13 +257,11 @@ public object TrueDispatch(ArrayList args) return null; } - Object result = null; + object result = null; if (!Converter.ToManaged(op, rtype, out result, false)) { - string s = "could not convert Python result to " + - rtype.ToString(); Runtime.XDecref(op); - throw new ConversionException(s); + throw new ConversionException($"could not convert Python result to {rtype}"); } Runtime.XDecref(op); @@ -283,9 +270,9 @@ public object TrueDispatch(ArrayList args) } - public class ConversionException : System.Exception + public class ConversionException : Exception { - public ConversionException() : base() + public ConversionException() { } @@ -293,4 +280,4 @@ public ConversionException(string msg) : base(msg) { } } -} \ No newline at end of file +} diff --git a/src/runtime/delegateobject.cs b/src/runtime/delegateobject.cs index 61e91942b..e1103cbc7 100644 --- a/src/runtime/delegateobject.cs +++ b/src/runtime/delegateobject.cs @@ -1,6 +1,4 @@ using System; -using System.Reflection; -using System.Runtime.InteropServices; namespace Python.Runtime { @@ -12,7 +10,7 @@ namespace Python.Runtime /// internal class DelegateObject : ClassBase { - MethodBinder binder; + private MethodBinder binder; internal DelegateObject(Type tp) : base(tp) { @@ -20,17 +18,16 @@ internal DelegateObject(Type tp) : base(tp) } - //==================================================================== - // Given a PyObject pointer to an instance of a delegate type, return - // the true managed delegate the Python object represents (or null). - //==================================================================== - + /// + /// Given a PyObject pointer to an instance of a delegate type, return + /// the true managed delegate the Python object represents (or null). + /// private static Delegate GetTrueDelegate(IntPtr op) { - CLRObject o = GetManagedObject(op) as CLRObject; + var o = GetManagedObject(op) as CLRObject; if (o != null) { - Delegate d = o.inst as Delegate; + var d = o.inst as Delegate; return d; } return null; @@ -43,22 +40,20 @@ internal override bool CanSubclass() } - //==================================================================== - // DelegateObject __new__ implementation. The result of this is a new - // PyObject whose type is DelegateObject and whose ob_data is a handle - // to an actual delegate instance. The method wrapped by the actual - // delegate instance belongs to an object generated to relay the call - // to the Python callable passed in. - //==================================================================== - + /// + /// DelegateObject __new__ implementation. The result of this is a new + /// PyObject whose type is DelegateObject and whose ob_data is a handle + /// to an actual delegate instance. The method wrapped by the actual + /// delegate instance belongs to an object generated to relay the call + /// to the Python callable passed in. + /// public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { - DelegateObject self = (DelegateObject)GetManagedObject(tp); + var self = (DelegateObject)GetManagedObject(tp); if (Runtime.PyTuple_Size(args) != 1) { - string message = "class takes exactly one argument"; - return Exceptions.RaiseTypeError(message); + return Exceptions.RaiseTypeError("class takes exactly one argument"); } IntPtr method = Runtime.PyTuple_GetItem(args, 0); @@ -73,23 +68,22 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) } - //==================================================================== - // Implements __call__ for reflected delegate types. - //==================================================================== - + /// + /// Implements __call__ for reflected delegate types. + /// public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { - // todo: add fast type check! + // TODO: add fast type check! IntPtr pytype = Runtime.PyObject_TYPE(ob); - DelegateObject self = (DelegateObject)GetManagedObject(pytype); - CLRObject o = GetManagedObject(ob) as CLRObject; + var self = (DelegateObject)GetManagedObject(pytype); + var o = GetManagedObject(ob) as CLRObject; if (o == null) { return Exceptions.RaiseTypeError("invalid argument"); } - Delegate d = o.inst as Delegate; + var d = o.inst as Delegate; if (d == null) { @@ -99,11 +93,12 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) } - //==================================================================== - // Implements __cmp__ for reflected delegate types. - //==================================================================== -#if PYTHON3 - public static new IntPtr tp_richcompare(IntPtr ob, IntPtr other, int op) { + /// + /// Implements __cmp__ for reflected delegate types. + /// +#if PYTHON3 // TODO: Doesn't PY2 implement tp_richcompare too? + public new static IntPtr tp_richcompare(IntPtr ob, IntPtr other, int op) + { if (op != Runtime.Py_EQ && op != Runtime.Py_NE) { Runtime.XIncref(Runtime.PyNotImplemented); @@ -132,15 +127,11 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) return pyfalse; } #elif PYTHON2 - public static new int tp_compare(IntPtr ob, IntPtr other) + public static int tp_compare(IntPtr ob, IntPtr other) { Delegate d1 = GetTrueDelegate(ob); Delegate d2 = GetTrueDelegate(other); - if (d1 == d2) - { - return 0; - } - return -1; + return d1 == d2 ? 0 : -1; } #endif } diff --git a/src/runtime/eventbinding.cs b/src/runtime/eventbinding.cs index 6035c8e0b..b8b4c82ad 100644 --- a/src/runtime/eventbinding.cs +++ b/src/runtime/eventbinding.cs @@ -2,16 +2,15 @@ namespace Python.Runtime { - //======================================================================== - // Implements a Python event binding type, similar to a method binding. - //======================================================================== - + /// + /// Implements a Python event binding type, similar to a method binding. + /// internal class EventBinding : ExtensionType { - EventObject e; - IntPtr target; + private EventObject e; + private IntPtr target; - public EventBinding(EventObject e, IntPtr target) : base() + public EventBinding(EventObject e, IntPtr target) { Runtime.XIncref(target); this.target = target; @@ -19,19 +18,16 @@ public EventBinding(EventObject e, IntPtr target) : base() } - //==================================================================== - // EventBinding += operator implementation. - //==================================================================== - + /// + /// EventBinding += operator implementation. + /// public static IntPtr nb_inplace_add(IntPtr ob, IntPtr arg) { - EventBinding self = (EventBinding)GetManagedObject(ob); + var self = (EventBinding)GetManagedObject(ob); if (Runtime.PyCallable_Check(arg) < 1) { - Exceptions.SetError(Exceptions.TypeError, - "event handlers must be callable" - ); + Exceptions.SetError(Exceptions.TypeError, "event handlers must be callable"); return IntPtr.Zero; } @@ -45,19 +41,16 @@ public static IntPtr nb_inplace_add(IntPtr ob, IntPtr arg) } - //==================================================================== - // EventBinding -= operator implementation. - //==================================================================== - + /// + /// EventBinding -= operator implementation. + /// public static IntPtr nb_inplace_subtract(IntPtr ob, IntPtr arg) { - EventBinding self = (EventBinding)GetManagedObject(ob); + var self = (EventBinding)GetManagedObject(ob); if (Runtime.PyCallable_Check(arg) < 1) { - Exceptions.SetError(Exceptions.TypeError, - "invalid event handler" - ); + Exceptions.SetError(Exceptions.TypeError, "invalid event handler"); return IntPtr.Zero; } @@ -71,13 +64,12 @@ public static IntPtr nb_inplace_subtract(IntPtr ob, IntPtr arg) } - //==================================================================== - // EventBinding __hash__ implementation. - //==================================================================== - + /// + /// EventBinding __hash__ implementation. + /// public static IntPtr tp_hash(IntPtr ob) { - EventBinding self = (EventBinding)GetManagedObject(ob); + var self = (EventBinding)GetManagedObject(ob); long x = 0; long y = 0; @@ -107,28 +99,26 @@ public static IntPtr tp_hash(IntPtr ob) } - //==================================================================== - // EventBinding __repr__ implementation. - //==================================================================== - + /// + /// EventBinding __repr__ implementation. + /// public static IntPtr tp_repr(IntPtr ob) { - EventBinding self = (EventBinding)GetManagedObject(ob); - string type = (self.target == IntPtr.Zero) ? "unbound" : "bound"; - string s = String.Format("<{0} event '{1}'>", type, self.e.name); + var self = (EventBinding)GetManagedObject(ob); + string type = self.target == IntPtr.Zero ? "unbound" : "bound"; + string s = string.Format("<{0} event '{1}'>", type, self.e.name); return Runtime.PyString_FromString(s); } - //==================================================================== - // EventBinding dealloc implementation. - //==================================================================== - - public static new void tp_dealloc(IntPtr ob) + /// + /// EventBinding dealloc implementation. + /// + public new static void tp_dealloc(IntPtr ob) { - EventBinding self = (EventBinding)GetManagedObject(ob); + var self = (EventBinding)GetManagedObject(ob); Runtime.XDecref(self.target); ExtensionType.FinalizeObject(self); } } -} \ No newline at end of file +} diff --git a/src/runtime/eventobject.cs b/src/runtime/eventobject.cs index 6523f7e20..5f18c4609 100644 --- a/src/runtime/eventobject.cs +++ b/src/runtime/eventobject.cs @@ -4,10 +4,9 @@ namespace Python.Runtime { - //======================================================================== - // Implements a Python descriptor type that provides access to CLR events. - //======================================================================== - + /// + /// Implements a Python descriptor type that provides access to CLR events. + /// internal class EventObject : ExtensionType { internal string name; @@ -15,44 +14,41 @@ internal class EventObject : ExtensionType internal EventInfo info; internal Hashtable reg; - public EventObject(EventInfo info) : base() + public EventObject(EventInfo info) { this.name = info.Name; this.info = info; } - //==================================================================== - // Register a new Python object event handler with the event. - //==================================================================== - + /// + /// Register a new Python object event handler with the event. + /// internal bool AddEventHandler(IntPtr target, IntPtr handler) { - Object obj = null; + object obj = null; if (target != IntPtr.Zero) { - CLRObject co = (CLRObject)ManagedType.GetManagedObject(target); + var co = (CLRObject)GetManagedObject(target); obj = co.inst; } // Create a true delegate instance of the appropriate type to // wrap the Python handler. Note that wrapper delegate creation // always succeeds, though calling the wrapper may fail. - - Type type = this.info.EventHandlerType; + Type type = info.EventHandlerType; Delegate d = PythonEngine.DelegateManager.GetDelegate(type, handler); // Now register the handler in a mapping from instance to pairs // of (handler hash, delegate) so we can lookup to remove later. // All this is done lazily to avoid overhead until an event is // actually subscribed to by a Python event handler. - if (reg == null) { reg = new Hashtable(); } - object key = (obj != null) ? obj : this.info.ReflectedType; - ArrayList list = reg[key] as ArrayList; + object key = obj ?? info.ReflectedType; + var list = reg[key] as ArrayList; if (list == null) { list = new ArrayList(); @@ -62,54 +58,48 @@ internal bool AddEventHandler(IntPtr target, IntPtr handler) // Note that AddEventHandler helper only works for public events, // so we have to get the underlying add method explicitly. - object[] args = { d }; - MethodInfo mi = this.info.GetAddMethod(true); + MethodInfo mi = info.GetAddMethod(true); mi.Invoke(obj, BindingFlags.Default, null, args, null); return true; } - //==================================================================== - // Remove the given Python object event handler. - //==================================================================== - + /// + /// Remove the given Python object event handler. + /// internal bool RemoveEventHandler(IntPtr target, IntPtr handler) { - Object obj = null; + object obj = null; if (target != IntPtr.Zero) { - CLRObject co = (CLRObject)ManagedType.GetManagedObject(target); + var co = (CLRObject)GetManagedObject(target); obj = co.inst; } IntPtr hash = Runtime.PyObject_Hash(handler); - if (Exceptions.ErrorOccurred() || (reg == null)) + if (Exceptions.ErrorOccurred() || reg == null) { - Exceptions.SetError(Exceptions.ValueError, - "unknown event handler" - ); + Exceptions.SetError(Exceptions.ValueError, "unknown event handler"); return false; } - object key = (obj != null) ? obj : this.info.ReflectedType; - ArrayList list = reg[key] as ArrayList; + object key = obj ?? info.ReflectedType; + var list = reg[key] as ArrayList; if (list == null) { - Exceptions.SetError(Exceptions.ValueError, - "unknown event handler" - ); + Exceptions.SetError(Exceptions.ValueError, "unknown event handler"); return false; } object[] args = { null }; - MethodInfo mi = this.info.GetRemoveMethod(true); + MethodInfo mi = info.GetRemoveMethod(true); - for (int i = 0; i < list.Count; i++) + for (var i = 0; i < list.Count; i++) { - Handler item = (Handler)list[i]; + var item = (Handler)list[i]; if (item.hash != hash) { continue; @@ -127,21 +117,18 @@ internal bool RemoveEventHandler(IntPtr target, IntPtr handler) return true; } - Exceptions.SetError(Exceptions.ValueError, - "unknown event handler" - ); + Exceptions.SetError(Exceptions.ValueError, "unknown event handler"); return false; } - //==================================================================== - // Descriptor __get__ implementation. A getattr on an event returns - // a "bound" event that keeps a reference to the object instance. - //==================================================================== - + /// + /// Descriptor __get__ implementation. A getattr on an event returns + /// a "bound" event that keeps a reference to the object instance. + /// public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { - EventObject self = GetManagedObject(ds) as EventObject; + var self = GetManagedObject(ds) as EventObject; EventBinding binding; if (self == null) @@ -174,53 +161,48 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) } - //==================================================================== - // Descriptor __set__ implementation. This actually never allows you - // to set anything; it exists solely to support the '+=' spelling of - // event handler registration. The reason is that given code like: - // 'ob.SomeEvent += method', Python will attempt to set the attribute - // SomeEvent on ob to the result of the '+=' operation. - //==================================================================== - - public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) + /// + /// Descriptor __set__ implementation. This actually never allows you + /// to set anything; it exists solely to support the '+=' spelling of + /// event handler registration. The reason is that given code like: + /// 'ob.SomeEvent += method', Python will attempt to set the attribute + /// SomeEvent on ob to the result of the '+=' operation. + /// + public new static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { - EventBinding e = GetManagedObject(val) as EventBinding; + var e = GetManagedObject(val) as EventBinding; if (e != null) { return 0; } - string message = "cannot set event attributes"; - Exceptions.RaiseTypeError(message); + Exceptions.RaiseTypeError("cannot set event attributes"); return -1; } - //==================================================================== - // Descriptor __repr__ implementation. - //==================================================================== - + /// + /// Descriptor __repr__ implementation. + /// public static IntPtr tp_repr(IntPtr ob) { - EventObject self = (EventObject)GetManagedObject(ob); - string s = String.Format("", self.name); - return Runtime.PyString_FromString(s); + var self = (EventObject)GetManagedObject(ob); + return Runtime.PyString_FromString($""); } - //==================================================================== - // Descriptor dealloc implementation. - //==================================================================== - - public static new void tp_dealloc(IntPtr ob) + /// + /// Descriptor dealloc implementation. + /// + public new static void tp_dealloc(IntPtr ob) { - EventObject self = (EventObject)GetManagedObject(ob); + var self = (EventObject)GetManagedObject(ob); if (self.unbound != null) { Runtime.XDecref(self.unbound.pyHandle); } - ExtensionType.FinalizeObject(self); + FinalizeObject(self); } } @@ -236,4 +218,4 @@ public Handler(IntPtr hash, Delegate d) this.del = d; } } -} \ No newline at end of file +} diff --git a/src/runtime/exceptions.cs b/src/runtime/exceptions.cs index 429c09212..9023cfcfa 100644 --- a/src/runtime/exceptions.cs +++ b/src/runtime/exceptions.cs @@ -1,9 +1,7 @@ using System; using System.Reflection; -using System.Collections; using System.Runtime.InteropServices; - namespace Python.Runtime { /// @@ -25,12 +23,12 @@ internal ExceptionClassObject(Type tp) : base(tp) internal static Exception ToException(IntPtr ob) { - CLRObject co = GetManagedObject(ob) as CLRObject; + var co = GetManagedObject(ob) as CLRObject; if (co == null) { return null; } - Exception e = co.inst as Exception; + var e = co.inst as Exception; if (e == null) { return null; @@ -38,10 +36,9 @@ internal static Exception ToException(IntPtr ob) return e; } - //==================================================================== - // Exception __str__ implementation - //==================================================================== - + /// + /// Exception __str__ implementation + /// public new static IntPtr tp_str(IntPtr ob) { Exception e = ToException(ob); @@ -50,8 +47,8 @@ internal static Exception ToException(IntPtr ob) return Exceptions.RaiseTypeError("invalid object"); } - string message = String.Empty; - if (e.Message != String.Empty) + string message = string.Empty; + if (e.Message != string.Empty) { message = e.Message; } @@ -78,23 +75,19 @@ private Exceptions() { } - //=================================================================== - // Initialization performed on startup of the Python runtime. - //=================================================================== - + /// + /// Initialization performed on startup of the Python runtime. + /// internal static void Initialize() { -#if PYTHON3 - exceptions_module = Runtime.PyImport_ImportModule("builtins"); -#elif PYTHON2 - exceptions_module = Runtime.PyImport_ImportModule("exceptions"); -#endif + string exceptionsModuleName = Runtime.IsPython3 ? "builtins" : "exceptions"; + exceptions_module = Runtime.PyImport_ImportModule(exceptionsModuleName); + Exceptions.ErrorCheck(exceptions_module); warnings_module = Runtime.PyImport_ImportModule("warnings"); Exceptions.ErrorCheck(warnings_module); Type type = typeof(Exceptions); - foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | - BindingFlags.Static)) + foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | BindingFlags.Static)) { IntPtr op = Runtime.PyObject_GetAttrString(exceptions_module, fi.Name); if (op != IntPtr.Zero) @@ -104,26 +97,24 @@ internal static void Initialize() else { fi.SetValue(type, IntPtr.Zero); - DebugUtil.Print("Unknown exception: " + fi.Name); + DebugUtil.Print($"Unknown exception: {fi.Name}"); } } Runtime.PyErr_Clear(); } - //=================================================================== - // Cleanup resources upon shutdown of the Python runtime. - //=================================================================== - + /// + /// Cleanup resources upon shutdown of the Python runtime. + /// internal static void Shutdown() { - if (0 != Runtime.Py_IsInitialized()) + if (Runtime.Py_IsInitialized() != 0) { Type type = typeof(Exceptions); - foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | - BindingFlags.Static)) + foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | BindingFlags.Static)) { - IntPtr op = (IntPtr)fi.GetValue(type); + var op = (IntPtr)fi.GetValue(type); if (op != IntPtr.Zero) { Runtime.XDecref(op); @@ -142,19 +133,21 @@ internal static void Shutdown() /// __getattr__ implementation, and thus dereferencing a NULL /// pointer. /// - /// A CLR exception /// The python object wrapping internal static void SetArgsAndCause(IntPtr ob) { - var e = ExceptionClassObject.ToException(ob); + // e: A CLR Exception + Exception e = ExceptionClassObject.ToException(ob); if (e == null) + { return; + } IntPtr args; if (!string.IsNullOrEmpty(e.Message)) { args = Runtime.PyTuple_New(1); - var msg = Runtime.PyUnicode_FromString(e.Message); + IntPtr msg = Runtime.PyUnicode_FromString(e.Message); Runtime.PyTuple_SetItem(args, 0, msg); } else @@ -174,10 +167,10 @@ internal static void SetArgsAndCause(IntPtr ob) } /// - /// Shortcut for (pointer == NULL) -> throw PythonException + /// Shortcut for (pointer == NULL) -> throw PythonException /// /// Pointer to a Python object - internal unsafe static void ErrorCheck(IntPtr pointer) + internal static void ErrorCheck(IntPtr pointer) { if (pointer == IntPtr.Zero) { @@ -186,12 +179,11 @@ internal unsafe static void ErrorCheck(IntPtr pointer) } /// - /// Shortcut for (pointer == NULL or ErrorOccurred()) -> throw PythonException + /// Shortcut for (pointer == NULL or ErrorOccurred()) -> throw PythonException /// - /// Shortcut for (pointer == NULL) -> throw PythonException - internal unsafe static void ErrorOccurredCheck(IntPtr pointer) + internal static void ErrorOccurredCheck(IntPtr pointer) { - if ((pointer == IntPtr.Zero) || Exceptions.ErrorOccurred()) + if (pointer == IntPtr.Zero || ErrorOccurred()) { throw new PythonException(); } @@ -200,7 +192,6 @@ internal unsafe static void ErrorOccurredCheck(IntPtr pointer) /// /// ExceptionMatches Method /// - /// /// /// Returns true if the current Python exception matches the given /// Python object. This is a wrapper for PyErr_ExceptionMatches. @@ -213,7 +204,6 @@ public static bool ExceptionMatches(IntPtr ob) /// /// ExceptionMatches Method /// - /// /// /// Returns true if the given Python exception matches the given /// Python object. This is a wrapper for PyErr_GivenExceptionMatches. @@ -221,13 +211,12 @@ public static bool ExceptionMatches(IntPtr ob) public static bool ExceptionMatches(IntPtr exc, IntPtr ob) { int i = Runtime.PyErr_GivenExceptionMatches(exc, ob); - return (i != 0); + return i != 0; } /// /// SetError Method /// - /// /// /// Sets the current Python exception given a native string. /// This is a wrapper for the Python PyErr_SetString call. @@ -240,7 +229,6 @@ public static void SetError(IntPtr ob, string value) /// /// SetError Method /// - /// /// /// Sets the current Python exception given a Python object. /// This is a wrapper for the Python PyErr_SetObject call. @@ -253,7 +241,6 @@ public static void SetError(IntPtr ob, IntPtr value) /// /// SetError Method /// - /// /// /// Sets the current Python exception given a CLR exception /// object. The CLR exception instance is wrapped as a Python @@ -261,12 +248,12 @@ public static void SetError(IntPtr ob, IntPtr value) /// public static void SetError(Exception e) { - // Because delegates allow arbitrary nestings of Python calling + // Because delegates allow arbitrary nesting of Python calling // managed calling Python calling... etc. it is possible that we // might get a managed exception raised that is a wrapper for a // Python exception. In that case we'd rather have the real thing. - PythonException pe = e as PythonException; + var pe = e as PythonException; if (pe != null) { Runtime.PyErr_SetObject(pe.PyType, pe.PyValue); @@ -283,7 +270,6 @@ public static void SetError(Exception e) /// /// ErrorOccurred Method /// - /// /// /// Returns true if an exception occurred in the Python runtime. /// This is a wrapper for the Python PyErr_Occurred call. @@ -296,7 +282,6 @@ public static bool ErrorOccurred() /// /// Clear Method /// - /// /// /// Clear any exception that has been set in the Python runtime. /// @@ -314,7 +299,7 @@ public static void Clear() /// public static void warn(string message, IntPtr exception, int stacklevel) { - if ((exception == IntPtr.Zero) || + if (exception == IntPtr.Zero || (Runtime.PyObject_IsSubclass(exception, Exceptions.Warning) != 1)) { Exceptions.RaiseTypeError("Invalid exception"); diff --git a/src/runtime/extensiontype.cs b/src/runtime/extensiontype.cs index 91ff5be2e..9569b0485 100644 --- a/src/runtime/extensiontype.cs +++ b/src/runtime/extensiontype.cs @@ -1,31 +1,30 @@ using System; using System.Runtime.InteropServices; -using System.Collections; -using System.Reflection; namespace Python.Runtime { /// /// Base class for extensions whose instances *share* a single Python /// type object, such as the types that represent CLR methods, fields, - /// etc. Instances implemented by this class do not support subtyping. + /// etc. Instances implemented by this class do not support sub-typing. /// internal abstract class ExtensionType : ManagedType { - public ExtensionType() : base() + public ExtensionType() { // Create a new PyObject whose type is a generated type that is - // implemented by the particuar concrete ExtensionType subclass. + // implemented by the particular concrete ExtensionType subclass. // The Python instance object is related to an instance of a // particular concrete subclass with a hidden CLR gchandle. - IntPtr tp = TypeManager.GetTypeHandle(this.GetType()); + IntPtr tp = TypeManager.GetTypeHandle(GetType()); -// int rc = (int)Marshal.ReadIntPtr(tp, TypeOffset.ob_refcnt); -// if (rc > 1050) { -// DebugUtil.Print("tp is: ", tp); -// DebugUtil.DumpType(tp); -// } + //int rc = (int)Marshal.ReadIntPtr(tp, TypeOffset.ob_refcnt); + //if (rc > 1050) + //{ + // DebugUtil.Print("tp is: ", tp); + // DebugUtil.DumpType(tp); + //} IntPtr py = Runtime.PyType_GenericAlloc(tp, 0); @@ -39,16 +38,15 @@ public ExtensionType() : base() Runtime.PyObject_GC_UnTrack(py); - this.tpHandle = tp; - this.pyHandle = py; - this.gcHandle = gc; + tpHandle = tp; + pyHandle = py; + gcHandle = gc; } - //==================================================================== - // Common finalization code to support custom tp_deallocs. - //==================================================================== - + /// + /// Common finalization code to support custom tp_deallocs. + /// public static void FinalizeObject(ManagedType self) { Runtime.PyObject_GC_Del(self.pyHandle); @@ -57,13 +55,12 @@ public static void FinalizeObject(ManagedType self) } - //==================================================================== - // Type __setattr__ implementation. - //==================================================================== - + /// + /// Type __setattr__ implementation. + /// public static int tp_setattro(IntPtr ob, IntPtr key, IntPtr val) { - string message = "type does not support setting attributes"; + var message = "type does not support setting attributes"; if (val == IntPtr.Zero) { message = "readonly attribute"; @@ -73,23 +70,20 @@ public static int tp_setattro(IntPtr ob, IntPtr key, IntPtr val) } - //==================================================================== - // Default __set__ implementation - this prevents descriptor instances - // being silently replaced in a type __dict__ by default __setattr__. - //==================================================================== - + /// + /// Default __set__ implementation - this prevents descriptor instances + /// being silently replaced in a type __dict__ by default __setattr__. + /// public static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { - string message = "attribute is read-only"; - Exceptions.SetError(Exceptions.AttributeError, message); + Exceptions.SetError(Exceptions.AttributeError, "attribute is read-only"); return -1; } - //==================================================================== - // Required Python GC support. - //==================================================================== - + /// + /// Required Python GC support. + /// public static int tp_traverse(IntPtr ob, IntPtr func, IntPtr args) { return 0; @@ -108,10 +102,9 @@ public static int tp_is_gc(IntPtr type) } - //==================================================================== - // Default dealloc implementation. - //==================================================================== - + /// + /// Default dealloc implementation. + /// public static void tp_dealloc(IntPtr ob) { // Clean up a Python instance of this extension type. This @@ -120,4 +113,4 @@ public static void tp_dealloc(IntPtr ob) FinalizeObject(self); } } -} \ No newline at end of file +} diff --git a/src/runtime/fieldobject.cs b/src/runtime/fieldobject.cs index d9740d9b1..7c9a466d5 100644 --- a/src/runtime/fieldobject.cs +++ b/src/runtime/fieldobject.cs @@ -1,33 +1,29 @@ using System; -using System.Collections; using System.Reflection; -using System.Runtime.InteropServices; namespace Python.Runtime { - //======================================================================== - // Implements a Python descriptor type that provides access to CLR fields. - //======================================================================== - + /// + /// Implements a Python descriptor type that provides access to CLR fields. + /// internal class FieldObject : ExtensionType { - FieldInfo info; + private FieldInfo info; - public FieldObject(FieldInfo info) : base() + public FieldObject(FieldInfo info) { this.info = info; } - //==================================================================== - // Descriptor __get__ implementation. This method returns the - // value of the field on the given object. The returned value - // is converted to an appropriately typed Python object. - //==================================================================== - + /// + /// Descriptor __get__ implementation. This method returns the + /// value of the field on the given object. The returned value + /// is converted to an appropriately typed Python object. + /// public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { - FieldObject self = (FieldObject)GetManagedObject(ds); - Object result; + var self = (FieldObject)GetManagedObject(ds); + object result; if (self == null) { @@ -36,14 +32,12 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) FieldInfo info = self.info; - if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) + if (ob == IntPtr.Zero || ob == Runtime.PyNone) { if (!info.IsStatic) { Exceptions.SetError(Exceptions.TypeError, - "instance attribute must be accessed " + - "through a class instance" - ); + "instance attribute must be accessed through a class instance"); return IntPtr.Zero; } try @@ -60,7 +54,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) try { - CLRObject co = (CLRObject)GetManagedObject(ob); + var co = (CLRObject)GetManagedObject(ob); result = info.GetValue(co.inst); return Converter.ToPython(result, info.FieldType); } @@ -71,16 +65,15 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) } } - //==================================================================== - // Descriptor __set__ implementation. This method sets the value of - // a field based on the given Python value. The Python value must be - // convertible to the type of the field. - //==================================================================== - - public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) + /// + /// Descriptor __set__ implementation. This method sets the value of + /// a field based on the given Python value. The Python value must be + /// convertible to the type of the field. + /// + public new static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { - FieldObject self = (FieldObject)GetManagedObject(ds); - Object newval; + var self = (FieldObject)GetManagedObject(ds); + object newval; if (self == null) { @@ -89,9 +82,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) if (val == IntPtr.Zero) { - Exceptions.SetError(Exceptions.TypeError, - "cannot delete field" - ); + Exceptions.SetError(Exceptions.TypeError, "cannot delete field"); return -1; } @@ -99,28 +90,22 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) if (info.IsLiteral || info.IsInitOnly) { - Exceptions.SetError(Exceptions.TypeError, - "field is read-only" - ); + Exceptions.SetError(Exceptions.TypeError, "field is read-only"); return -1; } bool is_static = info.IsStatic; - if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) + if (ob == IntPtr.Zero || ob == Runtime.PyNone) { if (!is_static) { - Exceptions.SetError(Exceptions.TypeError, - "instance attribute must be set " + - "through a class instance" - ); + Exceptions.SetError(Exceptions.TypeError, "instance attribute must be set through a class instance"); return -1; } } - if (!Converter.ToManaged(val, info.FieldType, out newval, - true)) + if (!Converter.ToManaged(val, info.FieldType, out newval, true)) { return -1; } @@ -129,7 +114,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { if (!is_static) { - CLRObject co = (CLRObject)GetManagedObject(ob); + var co = (CLRObject)GetManagedObject(ob); info.SetValue(co.inst, newval); } else @@ -145,15 +130,13 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) } } - //==================================================================== - // Descriptor __repr__ implementation. - //==================================================================== - + /// + /// Descriptor __repr__ implementation. + /// public static IntPtr tp_repr(IntPtr ob) { - FieldObject self = (FieldObject)GetManagedObject(ob); - string s = String.Format("", self.info.Name); - return Runtime.PyString_FromStringAndSize(s, s.Length); + var self = (FieldObject)GetManagedObject(ob); + return Runtime.PyString_FromString($""); } } -} \ No newline at end of file +} diff --git a/src/runtime/generictype.cs b/src/runtime/generictype.cs index d5caec38e..eeae801d2 100644 --- a/src/runtime/generictype.cs +++ b/src/runtime/generictype.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection; namespace Python.Runtime { @@ -15,28 +14,23 @@ internal GenericType(Type tp) : base(tp) { } - //==================================================================== - // Implements __new__ for reflected generic types. - //==================================================================== - + /// + /// Implements __new__ for reflected generic types. + /// public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { - Exceptions.SetError(Exceptions.TypeError, - "cannot instantiate an open generic type" - ); + Exceptions.SetError(Exceptions.TypeError, "cannot instantiate an open generic type"); return IntPtr.Zero; } - //==================================================================== - // Implements __call__ for reflected generic types. - //==================================================================== - + /// + /// Implements __call__ for reflected generic types. + /// public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { - Exceptions.SetError(Exceptions.TypeError, - "object is not callable"); + Exceptions.SetError(Exceptions.TypeError, "object is not callable"); return IntPtr.Zero; } } -} \ No newline at end of file +} diff --git a/src/runtime/genericutil.cs b/src/runtime/genericutil.cs index 18d59602a..9772d082f 100644 --- a/src/runtime/genericutil.cs +++ b/src/runtime/genericutil.cs @@ -1,9 +1,5 @@ using System; -using System.Runtime.InteropServices; using System.Collections.Generic; -using System.Collections; -using System.Reflection; -using System.Security; namespace Python.Runtime { @@ -13,7 +9,7 @@ namespace Python.Runtime /// internal class GenericUtil { - static Dictionary>> mapping; + private static Dictionary>> mapping; private GenericUtil() { @@ -21,18 +17,18 @@ private GenericUtil() static GenericUtil() { - mapping = new - Dictionary>>(); + mapping = new Dictionary>>(); } - //==================================================================== - // Register a generic type that appears in a given namespace. - //==================================================================== - + /// + /// Register a generic type that appears in a given namespace. + /// internal static void Register(Type t) { if (null == t.Namespace || null == t.Name) + { return; + } Dictionary> nsmap = null; mapping.TryGetValue(t.Namespace, out nsmap); @@ -57,10 +53,9 @@ internal static void Register(Type t) gnames.Add(t.Name); } - //==================================================================== - // xxx - //==================================================================== - + /// + /// xxx + /// public static List GetGenericBaseNames(string ns) { Dictionary> nsmap = null; @@ -69,7 +64,7 @@ public static List GetGenericBaseNames(string ns) { return null; } - List names = new List(); + var names = new List(); foreach (string key in nsmap.Keys) { names.Add(key); @@ -77,10 +72,9 @@ public static List GetGenericBaseNames(string ns) return names; } - //==================================================================== - // xxx - //==================================================================== - + /// + /// xxx + /// public static Type GenericForType(Type t, int paramCount) { return GenericByName(t.Namespace, t.Name, paramCount); @@ -91,7 +85,9 @@ public static Type GenericByName(string ns, string name, int paramCount) foreach (Type t in GenericsByName(ns, name)) { if (t.GetGenericArguments().Length == paramCount) + { return t; + } } return null; } @@ -123,7 +119,7 @@ public static List GenericsByName(string ns, string basename) return null; } - List result = new List(); + var result = new List(); foreach (string name in names) { string qname = ns + "." + name; @@ -137,10 +133,9 @@ public static List GenericsByName(string ns, string basename) return result; } - //==================================================================== - // xxx - //==================================================================== - + /// + /// xxx + /// public static string GenericNameForBaseName(string ns, string name) { Dictionary> nsmap = null; @@ -151,15 +146,11 @@ public static string GenericNameForBaseName(string ns, string name) } List gnames = null; nsmap.TryGetValue(name, out gnames); - if (gnames == null) - { - return null; - } - if (gnames.Count > 0) + if (gnames?.Count > 0) { return gnames[0]; } return null; } } -} \ No newline at end of file +} diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs index bdef98c27..bc9ac5eee 100644 --- a/src/runtime/importhook.cs +++ b/src/runtime/importhook.cs @@ -1,28 +1,33 @@ using System; -using System.Collections; using System.Runtime.InteropServices; namespace Python.Runtime { - //======================================================================== - // Implements the "import hook" used to integrate Python with the CLR. - //======================================================================== - + /// + /// Implements the "import hook" used to integrate Python with the CLR. + /// internal class ImportHook { - static IntPtr py_import; - static CLRModule root; - static MethodWrapper hook; + private static IntPtr py_import; + private static CLRModule root; + private static MethodWrapper hook; + private static IntPtr py_clr_module; #if PYTHON3 - static IntPtr py_clr_module; - static IntPtr module_def; -#endif + private static IntPtr module_def = IntPtr.Zero; - //=================================================================== - // Initialization performed on startup of the Python runtime. - //=================================================================== + internal static void InitializeModuleDef() + { + if (module_def == IntPtr.Zero) + { + module_def = ModuleDefOffset.AllocModuleDef("clr"); + } + } +#endif + /// + /// Initialization performed on startup of the Python runtime. + /// internal static void Initialize() { // Initialize the Python <--> CLR module hook. We replace the @@ -30,13 +35,12 @@ internal static void Initialize() // but it provides the most "Pythonic" way of dealing with CLR // modules (Python doesn't provide a way to emulate packages). IntPtr dict = Runtime.PyImport_GetModuleDict(); -#if PYTHON3 - IntPtr mod = Runtime.PyImport_ImportModule("builtins"); - py_import = Runtime.PyObject_GetAttrString(mod, "__import__"); -#elif PYTHON2 - IntPtr mod = Runtime.PyDict_GetItemString(dict, "__builtin__"); + + IntPtr mod = Runtime.IsPython3 + ? Runtime.PyImport_ImportModule("builtins") + : Runtime.PyDict_GetItemString(dict, "__builtin__"); + py_import = Runtime.PyObject_GetAttrString(mod, "__import__"); -#endif hook = new MethodWrapper(typeof(ImportHook), "__import__", "TernaryFunc"); Runtime.PyObject_SetAttrString(mod, "__import__", hook.ptr); Runtime.XDecref(hook.ptr); @@ -44,8 +48,8 @@ internal static void Initialize() root = new CLRModule(); #if PYTHON3 - // create a python module with the same methods as the clr module-like object - module_def = ModuleDefOffset.AllocModuleDef("clr"); + // create a python module with the same methods as the clr module-like object + InitializeModuleDef(); py_clr_module = Runtime.PyModule_Create2(module_def, 3); // both dicts are borrowed references @@ -54,78 +58,83 @@ internal static void Initialize() clr_dict = (IntPtr)Marshal.PtrToStructure(clr_dict, typeof(IntPtr)); Runtime.PyDict_Update(mod_dict, clr_dict); - Runtime.PyDict_SetItemString(dict, "CLR", py_clr_module); - Runtime.PyDict_SetItemString(dict, "clr", py_clr_module); #elif PYTHON2 Runtime.XIncref(root.pyHandle); // we are using the module two times - Runtime.PyDict_SetItemString(dict, "CLR", root.pyHandle); - Runtime.PyDict_SetItemString(dict, "clr", root.pyHandle); + py_clr_module = root.pyHandle; // Alias handle for PY2/PY3 #endif + Runtime.PyDict_SetItemString(dict, "CLR", py_clr_module); + Runtime.PyDict_SetItemString(dict, "clr", py_clr_module); } - //=================================================================== - // Cleanup resources upon shutdown of the Python runtime. - //=================================================================== - + /// + /// Cleanup resources upon shutdown of the Python runtime. + /// internal static void Shutdown() { -#if PYTHON3 - if (0 != Runtime.Py_IsInitialized()) { - Runtime.XDecref(py_clr_module); - Runtime.XDecref(root.pyHandle); - } - ModuleDefOffset.FreeModuleDef(module_def); -#elif PYTHON2 - if (0 != Runtime.Py_IsInitialized()) + if (Runtime.Py_IsInitialized() != 0) { + Runtime.XDecref(py_clr_module); Runtime.XDecref(root.pyHandle); - Runtime.XDecref(root.pyHandle); - } -#endif - if (0 != Runtime.Py_IsInitialized()) - { Runtime.XDecref(py_import); } } - //=================================================================== - // Return the clr python module (new reference) - //=================================================================== + /// + /// Return the clr python module (new reference) + /// public static IntPtr GetCLRModule(IntPtr? fromList = null) { root.InitializePreload(); -#if PYTHON3 - // update the module dictionary with the contents of the root dictionary + + if (Runtime.IsPython2) + { + Runtime.XIncref(py_clr_module); + return py_clr_module; + } + + // Python 3 + // update the module dictionary with the contents of the root dictionary root.LoadNames(); IntPtr py_mod_dict = Runtime.PyModule_GetDict(py_clr_module); IntPtr clr_dict = Runtime._PyObject_GetDictPtr(root.pyHandle); // PyObject** clr_dict = (IntPtr)Marshal.PtrToStructure(clr_dict, typeof(IntPtr)); Runtime.PyDict_Update(py_mod_dict, clr_dict); - // find any items from the fromlist and get them from the root if they're not - // aleady in the module dictionary - if (fromList != null && fromList != IntPtr.Zero) { + // find any items from the from list and get them from the root if they're not + // already in the module dictionary + if (fromList != null && fromList != IntPtr.Zero) + { if (Runtime.PyTuple_Check(fromList.GetValueOrDefault())) { Runtime.XIncref(py_mod_dict); - using(PyDict mod_dict = new PyDict(py_mod_dict)) { + using (var mod_dict = new PyDict(py_mod_dict)) + { Runtime.XIncref(fromList.GetValueOrDefault()); - using (PyTuple from = new PyTuple(fromList.GetValueOrDefault())) { - foreach (PyObject item in from) { + using (var from = new PyTuple(fromList.GetValueOrDefault())) + { + foreach (PyObject item in from) + { if (mod_dict.HasKey(item)) + { continue; + } - string s = item.AsManagedObject(typeof(string)) as string; - if (null == s) + var s = item.AsManagedObject(typeof(string)) as string; + if (s == null) + { continue; + } ManagedType attr = root.GetAttribute(s, true); - if (null == attr) + if (attr == null) + { continue; + } Runtime.XIncref(attr.pyHandle); - using (PyObject obj = new PyObject(attr.pyHandle)) { + using (var obj = new PyObject(attr.pyHandle)) + { mod_dict.SetItem(s, obj); } } @@ -133,19 +142,13 @@ public static IntPtr GetCLRModule(IntPtr? fromList = null) } } } - Runtime.XIncref(py_clr_module); return py_clr_module; -#elif PYTHON2 - Runtime.XIncref(root.pyHandle); - return root.pyHandle; -#endif } - //=================================================================== - // The actual import hook that ties Python to the managed world. - //=================================================================== - + /// + /// The actual import hook that ties Python to the managed world. + /// public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) { // Replacement for the builtin __import__. The original import @@ -155,15 +158,13 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) int num_args = Runtime.PyTuple_Size(args); if (num_args < 1) { - return Exceptions.RaiseTypeError( - "__import__() takes at least 1 argument (0 given)" - ); + return Exceptions.RaiseTypeError("__import__() takes at least 1 argument (0 given)"); } // borrowed reference IntPtr py_mod_name = Runtime.PyTuple_GetItem(args, 0); - if ((py_mod_name == IntPtr.Zero) || - (!Runtime.IsStringType(py_mod_name))) + if (py_mod_name == IntPtr.Zero || + !Runtime.IsStringType(py_mod_name)) { return Exceptions.RaiseTypeError("string expected"); } @@ -172,12 +173,12 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) // This determines whether we return the head or tail module. IntPtr fromList = IntPtr.Zero; - bool fromlist = false; + var fromlist = false; if (num_args >= 4) { fromList = Runtime.PyTuple_GetItem(args, 3); - if ((fromList != IntPtr.Zero) && - (Runtime.PyObject_IsTrue(fromList) == 1)) + if (fromList != IntPtr.Zero && + Runtime.PyObject_IsTrue(fromList) == 1) { fromlist = true; } @@ -202,8 +203,7 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) } if (mod_name == "CLR") { - Exceptions.deprecation("The CLR module is deprecated. " + - "Please use 'clr'."); + Exceptions.deprecation("The CLR module is deprecated. Please use 'clr'."); IntPtr clr_module = GetCLRModule(fromList); if (clr_module != IntPtr.Zero) { @@ -221,8 +221,7 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) { clr_prefix = "CLR."; // prepend when adding the module to sys.modules realname = mod_name.Substring(4); - string msg = String.Format("Importing from the CLR.* namespace " + - "is deprecated. Please import '{0}' directly.", realname); + string msg = $"Importing from the CLR.* namespace is deprecated. Please import '{realname}' directly."; Exceptions.deprecation(msg); } else @@ -283,7 +282,7 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) } // See if sys.modules for this interpreter already has the - // requested module. If so, just return the exising module. + // requested module. If so, just return the existing module. IntPtr modules = Runtime.PyImport_GetModuleDict(); IntPtr module = Runtime.PyDict_GetItem(modules, py_mod_name); @@ -314,18 +313,16 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) // enable preloading in a non-interactive python processing by // setting clr.preload = True - ModuleObject head = (mod_name == realname) ? null : root; + ModuleObject head = mod_name == realname ? null : root; ModuleObject tail = root; root.InitializePreload(); - for (int i = 0; i < names.Length; i++) + foreach (string name in names) { - string name = names[i]; ManagedType mt = tail.GetAttribute(name, true); if (!(mt is ModuleObject)) { - string error = String.Format("No module named {0}", name); - Exceptions.SetError(Exceptions.ImportError, error); + Exceptions.SetError(Exceptions.ImportError, $"No module named {name}"); return IntPtr.Zero; } if (head == null) @@ -339,16 +336,12 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) } // Add the module to sys.modules - Runtime.PyDict_SetItemString(modules, - tail.moduleName, - tail.pyHandle); + Runtime.PyDict_SetItemString(modules, tail.moduleName, tail.pyHandle); // If imported from CLR add CLR. to sys.modules as well if (clr_prefix != null) { - Runtime.PyDict_SetItemString(modules, - clr_prefix + tail.moduleName, - tail.pyHandle); + Runtime.PyDict_SetItemString(modules, clr_prefix + tail.moduleName, tail.pyHandle); } } @@ -357,7 +350,7 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) if (fromlist && Runtime.PySequence_Size(fromList) == 1) { IntPtr fp = Runtime.PySequence_GetItem(fromList, 0); - if ((!CLRModule.preload) && Runtime.GetManagedString(fp) == "*") + if (!CLRModule.preload && Runtime.GetManagedString(fp) == "*") { mod.LoadNames(); } diff --git a/src/runtime/indexer.cs b/src/runtime/indexer.cs index 86e290d5b..7b6d90ca8 100644 --- a/src/runtime/indexer.cs +++ b/src/runtime/indexer.cs @@ -1,14 +1,11 @@ using System; -using System.Collections; using System.Reflection; -using System.Security.Permissions; namespace Python.Runtime { - //======================================================================== - // Bundles the information required to support an indexer property. - //======================================================================== - + /// + /// Bundles the information required to support an indexer property. + /// internal class Indexer { public MethodBinder GetterBinder; @@ -60,28 +57,34 @@ internal void SetItem(IntPtr inst, IntPtr args) internal bool NeedsDefaultArgs(IntPtr args) { int pynargs = Runtime.PyTuple_Size(args); - var methods = SetterBinder.GetMethods(); + MethodBase[] methods = SetterBinder.GetMethods(); if (methods.Length == 0) + { return false; + } MethodBase mi = methods[0]; ParameterInfo[] pi = mi.GetParameters(); // need to subtract one for the value int clrnargs = pi.Length - 1; if (pynargs == clrnargs || pynargs > clrnargs) + { return false; + } for (int v = pynargs; v < clrnargs; v++) { if (pi[v].DefaultValue == DBNull.Value) + { return false; + } } return true; } /// /// This will return default arguments a new instance of a tuple. The size - /// of the tuple will indicate the number of default arguments. + /// of the tuple will indicate the number of default arguments. /// /// This is pointing to the tuple args passed in /// a new instance of the tuple containing the default args @@ -89,26 +92,27 @@ internal IntPtr GetDefaultArgs(IntPtr args) { // if we don't need default args return empty tuple if (!NeedsDefaultArgs(args)) + { return Runtime.PyTuple_New(0); + } int pynargs = Runtime.PyTuple_Size(args); // Get the default arg tuple - var methods = SetterBinder.GetMethods(); + MethodBase[] methods = SetterBinder.GetMethods(); MethodBase mi = methods[0]; ParameterInfo[] pi = mi.GetParameters(); int clrnargs = pi.Length - 1; IntPtr defaultArgs = Runtime.PyTuple_New(clrnargs - pynargs); - for (int i = 0; i < (clrnargs - pynargs); i++) + for (var i = 0; i < clrnargs - pynargs; i++) { if (pi[i + pynargs].DefaultValue == DBNull.Value) - continue; - else { - IntPtr arg = Converter.ToPython(pi[i + pynargs].DefaultValue, pi[i + pynargs].ParameterType); - Runtime.PyTuple_SetItem(defaultArgs, i, arg); + continue; } + IntPtr arg = Converter.ToPython(pi[i + pynargs].DefaultValue, pi[i + pynargs].ParameterType); + Runtime.PyTuple_SetItem(defaultArgs, i, arg); } return defaultArgs; } } -} \ No newline at end of file +} diff --git a/src/runtime/interfaceobject.cs b/src/runtime/interfaceobject.cs index f550a95a8..ce1bc9eb0 100644 --- a/src/runtime/interfaceobject.cs +++ b/src/runtime/interfaceobject.cs @@ -16,69 +16,62 @@ internal class InterfaceObject : ClassBase internal InterfaceObject(Type tp) : base(tp) { - CoClassAttribute coclass = (CoClassAttribute) - Attribute.GetCustomAttribute(tp, cc_attr); + var coclass = (CoClassAttribute)Attribute.GetCustomAttribute(tp, cc_attr); if (coclass != null) { ctor = coclass.CoClass.GetConstructor(Type.EmptyTypes); } } - static Type cc_attr; + private static Type cc_attr; static InterfaceObject() { cc_attr = typeof(CoClassAttribute); } - //==================================================================== - // Implements __new__ for reflected interface types. - //==================================================================== - + /// + /// Implements __new__ for reflected interface types. + /// public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { - InterfaceObject self = (InterfaceObject)GetManagedObject(tp); + var self = (InterfaceObject)GetManagedObject(tp); int nargs = Runtime.PyTuple_Size(args); Type type = self.type; - Object obj; + object obj; if (nargs == 1) { IntPtr inst = Runtime.PyTuple_GetItem(args, 0); - CLRObject co = GetManagedObject(inst) as CLRObject; + var co = GetManagedObject(inst) as CLRObject; - if ((co == null) || (!type.IsInstanceOfType(co.inst))) + if (co == null || !type.IsInstanceOfType(co.inst)) { - string msg = "object does not implement " + type.Name; - Exceptions.SetError(Exceptions.TypeError, msg); + Exceptions.SetError(Exceptions.TypeError, $"object does not implement {type.Name}"); return IntPtr.Zero; } obj = co.inst; } - else if ((nargs == 0) && (self.ctor != null)) + else if (nargs == 0 && self.ctor != null) { obj = self.ctor.Invoke(null); if (obj == null || !type.IsInstanceOfType(obj)) { - Exceptions.SetError(Exceptions.TypeError, - "CoClass default constructor failed" - ); + Exceptions.SetError(Exceptions.TypeError, "CoClass default constructor failed"); return IntPtr.Zero; } } else { - Exceptions.SetError(Exceptions.TypeError, - "interface takes exactly one argument" - ); + Exceptions.SetError(Exceptions.TypeError, "interface takes exactly one argument"); return IntPtr.Zero; } return CLRObject.GetInstHandle(obj, self.pyHandle); } } -} \ No newline at end of file +} diff --git a/src/runtime/interfaces.cs b/src/runtime/interfaces.cs index 28f343529..5ce319858 100644 --- a/src/runtime/interfaces.cs +++ b/src/runtime/interfaces.cs @@ -1,6 +1,4 @@ using System; -using System.Reflection; -using System.Runtime.InteropServices; namespace Python.Runtime { @@ -29,4 +27,4 @@ internal interface IReflectedArray : IReflectedType internal interface IReflectedGenericClass : IReflectedClass { } -} \ No newline at end of file +} diff --git a/src/runtime/interop.cs b/src/runtime/interop.cs index 0657bc3e6..4ae4b61e0 100644 --- a/src/runtime/interop.cs +++ b/src/runtime/interop.cs @@ -7,13 +7,12 @@ namespace Python.Runtime { - //======================================================================= - // This file defines objects to support binary interop with the Python - // runtime. Generally, the definitions here need to be kept up to date - // when moving to new Python versions. - //======================================================================= - - [Serializable()] + /// + /// This file defines objects to support binary interop with the Python + /// runtime. Generally, the definitions here need to be kept up to date + /// when moving to new Python versions. + /// + [Serializable] [AttributeUsage(AttributeTargets.All)] public class DocStringAttribute : Attribute { @@ -31,7 +30,7 @@ public string DocString private string docStr; } - [Serializable()] + [Serializable] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)] internal class PythonMethodAttribute : Attribute { @@ -40,7 +39,7 @@ public PythonMethodAttribute() } } - [Serializable()] + [Serializable] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)] internal class ModuleFunctionAttribute : Attribute { @@ -49,7 +48,7 @@ public ModuleFunctionAttribute() } } - [Serializable()] + [Serializable] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)] internal class ForbidPythonThreadsAttribute : Attribute { @@ -59,7 +58,7 @@ public ForbidPythonThreadsAttribute() } - [Serializable()] + [Serializable] [AttributeUsage(AttributeTargets.Property)] internal class ModulePropertyAttribute : Attribute { @@ -75,22 +74,22 @@ internal class ObjectOffset static ObjectOffset() { int size = IntPtr.Size; - int n = 0; // Py_TRACE_REFS add two pointers to PyObject_HEAD -#if Py_DEBUG + var n = 0; // Py_TRACE_REFS add two pointers to PyObject_HEAD +#if PYTHON_WITH_PYDEBUG _ob_next = 0; _ob_prev = 1 * size; n = 2; #endif - ob_refcnt = (n + 0)*size; - ob_type = (n + 1)*size; - ob_dict = (n + 2)*size; - ob_data = (n + 3)*size; + ob_refcnt = (n + 0) * size; + ob_type = (n + 1) * size; + ob_dict = (n + 2) * size; + ob_data = (n + 3) * size; } public static int magic(IntPtr ob) { if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) || - (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException)))) + (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException)))) { return ExceptionOffset.ob_data; } @@ -100,7 +99,7 @@ public static int magic(IntPtr ob) public static int DictOffset(IntPtr ob) { if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) || - (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException)))) + (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException)))) { return ExceptionOffset.ob_dict; } @@ -110,18 +109,18 @@ public static int DictOffset(IntPtr ob) public static int Size(IntPtr ob) { if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) || - (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException)))) + (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException)))) { return ExceptionOffset.Size(); } -#if Py_DEBUG +#if PYTHON_WITH_PYDEBUG return 6 * IntPtr.Size; #else return 4 * IntPtr.Size; #endif } -#if Py_DEBUG +#if PYTHON_WITH_PYDEBUG public static int _ob_next; public static int _ob_prev; #endif @@ -186,7 +185,7 @@ static BytesOffset() /* The *real* layout of a type object when allocated on the heap */ //typedef struct _heaptypeobject { -#if Py_DEBUG // #ifdef Py_TRACE_REFS +#if PYTHON_WITH_PYDEBUG /* _PyObject_HEAD_EXTRA defines pointers to support a doubly-linked list of all live heap objects. */ public static int _ob_next = 0; public static int _ob_prev = 0; @@ -196,7 +195,7 @@ static BytesOffset() public static int ob_refcnt = 0; public static int ob_type = 0; // } - public static int ob_size = 0; /* Number of items in _VAR_iable part */ + public static int ob_size = 0; /* Number of items in _VAR_iable part */ // } public static int ob_shash = 0; public static int ob_sval = 0; /* start of data */ @@ -223,11 +222,12 @@ static ModuleDefOffset() } } - public static IntPtr AllocModuleDef(string modulename) { + public static IntPtr AllocModuleDef(string modulename) + { byte[] ascii = Encoding.ASCII.GetBytes(modulename); int size = name + ascii.Length + 1; IntPtr ptr = Marshal.AllocHGlobal(size); - for (int i = 0; i <= m_free; i += IntPtr.Size) + for (int i = 0; i < m_free; i += IntPtr.Size) Marshal.WriteIntPtr(ptr, i, IntPtr.Zero); Marshal.Copy(ascii, 0, (IntPtr)(ptr + name), ascii.Length); Marshal.WriteIntPtr(ptr, m_name, (IntPtr)(ptr + name)); @@ -235,7 +235,8 @@ public static IntPtr AllocModuleDef(string modulename) { return ptr; } - public static void FreeModuleDef(IntPtr ptr) { + public static void FreeModuleDef(IntPtr ptr) + { Marshal.FreeHGlobal(ptr); } @@ -268,8 +269,7 @@ public static void FreeModuleDef(IntPtr ptr) { /// internal class TypeFlags { -#if PYTHON2 - // these flags were removed in Python 3 +#if PYTHON2 // these flags were removed in Python 3 public static int HaveGetCharBuffer = (1 << 0); public static int HaveSequenceIn = (1 << 1); public static int GC = 0; @@ -307,8 +307,7 @@ internal class TypeFlags public static int BaseExceptionSubclass = (1 << 30); public static int TypeSubclass = (1 << 31); -#if PYTHON2 - // Default flags for Python 2 +#if PYTHON2 // Default flags for Python 2 public static int Default = ( HaveGetCharBuffer | HaveSequenceIn | @@ -318,13 +317,12 @@ internal class TypeFlags HaveIter | HaveClass | HaveStacklessExtension | - HaveIndex | - 0); -#elif PYTHON3 - // Default flags for Python 3 + HaveIndex | + 0); +#elif PYTHON3 // Default flags for Python 3 public static int Default = ( - HaveStacklessExtension | - HaveVersionTag); + HaveStacklessExtension | + HaveVersionTag); #endif } @@ -336,8 +334,8 @@ internal class TypeFlags internal class Interop { - static ArrayList keepAlive; - static Hashtable pmap; + private static ArrayList keepAlive; + private static Hashtable pmap; static Interop() { diff --git a/src/runtime/interop26.cs b/src/runtime/interop26.cs deleted file mode 100644 index 71e3c5115..000000000 --- a/src/runtime/interop26.cs +++ /dev/null @@ -1,150 +0,0 @@ -// Auto-generated by geninterop.py. -// DO NOT MODIFIY BY HAND. - - -#if PYTHON26 -using System; -using System.Collections; -using System.Collections.Specialized; -using System.Runtime.InteropServices; -using System.Reflection; -using System.Text; - -namespace Python.Runtime -{ - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal class TypeOffset - { - static TypeOffset() - { - Type type = typeof(TypeOffset); - FieldInfo[] fi = type.GetFields(); - int size = IntPtr.Size; - for (int i = 0; i < fi.Length; i++) - { - fi[i].SetValue(null, i * size); - } - } - - public static int magic() - { - return ob_size; - } - - // Auto-generated from PyHeapTypeObject in Python.h - public static int ob_refcnt = 0; - public static int ob_type = 0; - public static int ob_size = 0; - public static int tp_name = 0; - public static int tp_basicsize = 0; - public static int tp_itemsize = 0; - public static int tp_dealloc = 0; - public static int tp_print = 0; - public static int tp_getattr = 0; - public static int tp_setattr = 0; - public static int tp_compare = 0; - public static int tp_repr = 0; - public static int tp_as_number = 0; - public static int tp_as_sequence = 0; - public static int tp_as_mapping = 0; - public static int tp_hash = 0; - public static int tp_call = 0; - public static int tp_str = 0; - public static int tp_getattro = 0; - public static int tp_setattro = 0; - public static int tp_as_buffer = 0; - public static int tp_flags = 0; - public static int tp_doc = 0; - public static int tp_traverse = 0; - public static int tp_clear = 0; - public static int tp_richcompare = 0; - public static int tp_weaklistoffset = 0; - public static int tp_iter = 0; - public static int tp_iternext = 0; - public static int tp_methods = 0; - public static int tp_members = 0; - public static int tp_getset = 0; - public static int tp_base = 0; - public static int tp_dict = 0; - public static int tp_descr_get = 0; - public static int tp_descr_set = 0; - public static int tp_dictoffset = 0; - public static int tp_init = 0; - public static int tp_alloc = 0; - public static int tp_new = 0; - public static int tp_free = 0; - public static int tp_is_gc = 0; - public static int tp_bases = 0; - public static int tp_mro = 0; - public static int tp_cache = 0; - public static int tp_subclasses = 0; - public static int tp_weaklist = 0; - public static int tp_del = 0; - public static int tp_version_tag = 0; - public static int nb_add = 0; - public static int nb_subtract = 0; - public static int nb_multiply = 0; - public static int nb_divide = 0; - public static int nb_remainder = 0; - public static int nb_divmod = 0; - public static int nb_power = 0; - public static int nb_negative = 0; - public static int nb_positive = 0; - public static int nb_absolute = 0; - public static int nb_nonzero = 0; - public static int nb_invert = 0; - public static int nb_lshift = 0; - public static int nb_rshift = 0; - public static int nb_and = 0; - public static int nb_xor = 0; - public static int nb_or = 0; - public static int nb_coerce = 0; - public static int nb_int = 0; - public static int nb_long = 0; - public static int nb_float = 0; - public static int nb_oct = 0; - public static int nb_hex = 0; - public static int nb_inplace_add = 0; - public static int nb_inplace_subtract = 0; - public static int nb_inplace_multiply = 0; - public static int nb_inplace_divide = 0; - public static int nb_inplace_remainder = 0; - public static int nb_inplace_power = 0; - public static int nb_inplace_lshift = 0; - public static int nb_inplace_rshift = 0; - public static int nb_inplace_and = 0; - public static int nb_inplace_xor = 0; - public static int nb_inplace_or = 0; - public static int nb_floor_divide = 0; - public static int nb_true_divide = 0; - public static int nb_inplace_floor_divide = 0; - public static int nb_inplace_true_divide = 0; - public static int nb_index = 0; - public static int mp_length = 0; - public static int mp_subscript = 0; - public static int mp_ass_subscript = 0; - public static int sq_length = 0; - public static int sq_concat = 0; - public static int sq_repeat = 0; - public static int sq_item = 0; - public static int sq_slice = 0; - public static int sq_ass_item = 0; - public static int sq_ass_slice = 0; - public static int sq_contains = 0; - public static int sq_inplace_concat = 0; - public static int sq_inplace_repeat = 0; - public static int bf_getreadbuffer = 0; - public static int bf_getwritebuffer = 0; - public static int bf_getsegcount = 0; - public static int bf_getcharbuffer = 0; - public static int bf_getbuffer = 0; - public static int bf_releasebuffer = 0; - public static int name = 0; - public static int ht_slots = 0; - - /* here are optional user slots, followed by the members. */ - public static int members = 0; - } -} - -#endif diff --git a/src/runtime/interop32.cs b/src/runtime/interop32.cs deleted file mode 100644 index 2f7464233..000000000 --- a/src/runtime/interop32.cs +++ /dev/null @@ -1,141 +0,0 @@ -// Auto-generated by geninterop.py. -// DO NOT MODIFIY BY HAND. - - -#if PYTHON32 -using System; -using System.Collections; -using System.Collections.Specialized; -using System.Runtime.InteropServices; -using System.Reflection; -using System.Text; - -namespace Python.Runtime -{ - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal class TypeOffset - { - static TypeOffset() - { - Type type = typeof(TypeOffset); - FieldInfo[] fi = type.GetFields(); - int size = IntPtr.Size; - for (int i = 0; i < fi.Length; i++) - { - fi[i].SetValue(null, i * size); - } - } - - public static int magic() - { - return ob_size; - } - - // Auto-generated from PyHeapTypeObject in Python.h - public static int ob_refcnt = 0; - public static int ob_type = 0; - public static int ob_size = 0; - public static int tp_name = 0; - public static int tp_basicsize = 0; - public static int tp_itemsize = 0; - public static int tp_dealloc = 0; - public static int tp_print = 0; - public static int tp_getattr = 0; - public static int tp_setattr = 0; - public static int tp_reserved = 0; - public static int tp_repr = 0; - public static int tp_as_number = 0; - public static int tp_as_sequence = 0; - public static int tp_as_mapping = 0; - public static int tp_hash = 0; - public static int tp_call = 0; - public static int tp_str = 0; - public static int tp_getattro = 0; - public static int tp_setattro = 0; - public static int tp_as_buffer = 0; - public static int tp_flags = 0; - public static int tp_doc = 0; - public static int tp_traverse = 0; - public static int tp_clear = 0; - public static int tp_richcompare = 0; - public static int tp_weaklistoffset = 0; - public static int tp_iter = 0; - public static int tp_iternext = 0; - public static int tp_methods = 0; - public static int tp_members = 0; - public static int tp_getset = 0; - public static int tp_base = 0; - public static int tp_dict = 0; - public static int tp_descr_get = 0; - public static int tp_descr_set = 0; - public static int tp_dictoffset = 0; - public static int tp_init = 0; - public static int tp_alloc = 0; - public static int tp_new = 0; - public static int tp_free = 0; - public static int tp_is_gc = 0; - public static int tp_bases = 0; - public static int tp_mro = 0; - public static int tp_cache = 0; - public static int tp_subclasses = 0; - public static int tp_weaklist = 0; - public static int tp_del = 0; - public static int tp_version_tag = 0; - public static int nb_add = 0; - public static int nb_subtract = 0; - public static int nb_multiply = 0; - public static int nb_remainder = 0; - public static int nb_divmod = 0; - public static int nb_power = 0; - public static int nb_negative = 0; - public static int nb_positive = 0; - public static int nb_absolute = 0; - public static int nb_bool = 0; - public static int nb_invert = 0; - public static int nb_lshift = 0; - public static int nb_rshift = 0; - public static int nb_and = 0; - public static int nb_xor = 0; - public static int nb_or = 0; - public static int nb_int = 0; - public static int nb_reserved = 0; - public static int nb_float = 0; - public static int nb_inplace_add = 0; - public static int nb_inplace_subtract = 0; - public static int nb_inplace_multiply = 0; - public static int nb_inplace_remainder = 0; - public static int nb_inplace_power = 0; - public static int nb_inplace_lshift = 0; - public static int nb_inplace_rshift = 0; - public static int nb_inplace_and = 0; - public static int nb_inplace_xor = 0; - public static int nb_inplace_or = 0; - public static int nb_floor_divide = 0; - public static int nb_true_divide = 0; - public static int nb_inplace_floor_divide = 0; - public static int nb_inplace_true_divide = 0; - public static int nb_index = 0; - public static int mp_length = 0; - public static int mp_subscript = 0; - public static int mp_ass_subscript = 0; - public static int sq_length = 0; - public static int sq_concat = 0; - public static int sq_repeat = 0; - public static int sq_item = 0; - public static int was_sq_slice = 0; - public static int sq_ass_item = 0; - public static int was_sq_ass_slice = 0; - public static int sq_contains = 0; - public static int sq_inplace_concat = 0; - public static int sq_inplace_repeat = 0; - public static int bf_getbuffer = 0; - public static int bf_releasebuffer = 0; - public static int name = 0; - public static int ht_slots = 0; - - /* here are optional user slots, followed by the members. */ - public static int members = 0; - } -} - -#endif diff --git a/src/runtime/iterator.cs b/src/runtime/iterator.cs index c9b232e5e..c7c60ab19 100644 --- a/src/runtime/iterator.cs +++ b/src/runtime/iterator.cs @@ -1,31 +1,28 @@ using System; using System.Collections; -using System.Reflection; namespace Python.Runtime { - //======================================================================== - // Implements a generic Python iterator for IEnumerable objects and - // managed array objects. This supports 'for i in object:' in Python. - //======================================================================== - + /// + /// Implements a generic Python iterator for IEnumerable objects and + /// managed array objects. This supports 'for i in object:' in Python. + /// internal class Iterator : ExtensionType { - IEnumerator iter; + private IEnumerator iter; - public Iterator(IEnumerator e) : base() + public Iterator(IEnumerator e) { - this.iter = e; + iter = e; } - //==================================================================== - // Implements support for the Python iteration protocol. - //==================================================================== - + /// + /// Implements support for the Python iteration protocol. + /// public static IntPtr tp_iternext(IntPtr ob) { - Iterator self = GetManagedObject(ob) as Iterator; + var self = GetManagedObject(ob) as Iterator; if (!self.iter.MoveNext()) { Exceptions.SetError(Exceptions.StopIteration, Runtime.PyNone); @@ -41,4 +38,4 @@ public static IntPtr tp_iter(IntPtr ob) return ob; } } -} \ No newline at end of file +} diff --git a/src/runtime/managedtype.cs b/src/runtime/managedtype.cs index 782865f93..3191da949 100644 --- a/src/runtime/managedtype.cs +++ b/src/runtime/managedtype.cs @@ -1,16 +1,13 @@ using System; using System.Runtime.InteropServices; -using System.Collections; -using System.Reflection; namespace Python.Runtime { - //======================================================================== - // Common base class for all objects that are implemented in managed - // code. It defines the common fields that associate CLR and Python - // objects and common utilities to convert between those identities. - //======================================================================== - + /// + /// Common base class for all objects that are implemented in managed + /// code. It defines the common fields that associate CLR and Python + /// objects and common utilities to convert between those identities. + /// internal abstract class ManagedType { internal GCHandle gcHandle; // Native handle @@ -18,10 +15,9 @@ internal abstract class ManagedType internal IntPtr tpHandle; // PyType * - //==================================================================== - // Given a Python object, return the associated managed object or null. - //==================================================================== - + /// + /// Given a Python object, return the associated managed object or null. + /// internal static ManagedType GetManagedObject(IntPtr ob) { if (ob != IntPtr.Zero) @@ -32,13 +28,17 @@ internal static ManagedType GetManagedObject(IntPtr ob) tp = ob; } - int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags); + var flags = Util.ReadCLong(tp, TypeOffset.tp_flags); if ((flags & TypeFlags.Managed) != 0) { - IntPtr op = (tp == ob) + IntPtr op = tp == ob ? Marshal.ReadIntPtr(tp, TypeOffset.magic()) : Marshal.ReadIntPtr(ob, ObjectOffset.magic(ob)); - GCHandle gc = (GCHandle)op; + if (op == IntPtr.Zero) + { + return null; + } + var gc = (GCHandle)op; return (ManagedType)gc.Target; } } @@ -51,9 +51,7 @@ internal static ManagedType GetManagedObjectErr(IntPtr ob) ManagedType result = GetManagedObject(ob); if (result == null) { - Exceptions.SetError(Exceptions.TypeError, - "invalid argument, expected CLR type" - ); + Exceptions.SetError(Exceptions.TypeError, "invalid argument, expected CLR type"); } return result; } @@ -69,7 +67,7 @@ internal static bool IsManagedType(IntPtr ob) tp = ob; } - int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags); + var flags = Util.ReadCLong(tp, TypeOffset.tp_flags); if ((flags & TypeFlags.Managed) != 0) { return true; @@ -78,4 +76,4 @@ internal static bool IsManagedType(IntPtr ob) return false; } } -} \ No newline at end of file +} diff --git a/src/runtime/metatype.cs b/src/runtime/metatype.cs index b2ad78078..3295ab110 100644 --- a/src/runtime/metatype.cs +++ b/src/runtime/metatype.cs @@ -1,25 +1,21 @@ using System; using System.Runtime.InteropServices; -using System.Collections; -using System.Reflection; namespace Python.Runtime { - //======================================================================== - // The managed metatype. This object implements the type of all reflected - // types. It also provides support for single-inheritance from reflected - // managed types. - //======================================================================== - + /// + /// The managed metatype. This object implements the type of all reflected + /// types. It also provides support for single-inheritance from reflected + /// managed types. + /// internal class MetaType : ManagedType { - static IntPtr PyCLRMetaType; - + private static IntPtr PyCLRMetaType; - //==================================================================== - // Metatype initialization. This bootstraps the CLR metatype to life. - //==================================================================== + /// + /// Metatype initialization. This bootstraps the CLR metatype to life. + /// public static IntPtr Initialize() { PyCLRMetaType = TypeManager.CreateMetaType(typeof(MetaType)); @@ -27,11 +23,10 @@ public static IntPtr Initialize() } - //==================================================================== - // Metatype __new__ implementation. This is called to create a new - // class / type when a reflected class is subclassed. - //==================================================================== - + /// + /// Metatype __new__ implementation. This is called to create a new + /// class / type when a reflected class is subclassed. + /// public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { int len = Runtime.PyTuple_Size(args); @@ -51,15 +46,13 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) if (Runtime.PyTuple_Size(bases) != 1) { - return Exceptions.RaiseTypeError( - "cannot use multiple inheritance with managed classes" - ); + return Exceptions.RaiseTypeError("cannot use multiple inheritance with managed classes"); } IntPtr base_type = Runtime.PyTuple_GetItem(bases, 0); IntPtr mt = Runtime.PyObject_TYPE(base_type); - if (!((mt == PyCLRMetaType) || (mt == Runtime.PyTypeType))) + if (!(mt == PyCLRMetaType || mt == Runtime.PyTypeType)) { return Exceptions.RaiseTypeError("invalid metatype"); } @@ -67,23 +60,19 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) // Ensure that the reflected type is appropriate for subclassing, // disallowing subclassing of delegates, enums and array types. - ClassBase cb = GetManagedObject(base_type) as ClassBase; + var cb = GetManagedObject(base_type) as ClassBase; if (cb != null) { if (!cb.CanSubclass()) { - return Exceptions.RaiseTypeError( - "delegates, enums and array types cannot be subclassed" - ); + return Exceptions.RaiseTypeError("delegates, enums and array types cannot be subclassed"); } } IntPtr slots = Runtime.PyDict_GetItemString(dict, "__slots__"); if (slots != IntPtr.Zero) { - return Exceptions.RaiseTypeError( - "subclasses of managed classes do not support __slots__" - ); + return Exceptions.RaiseTypeError("subclasses of managed classes do not support __slots__"); } // If __assembly__ or __namespace__ are in the class dictionary then create @@ -93,16 +82,17 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) if (IntPtr.Zero != dict) { Runtime.XIncref(dict); - using (PyDict clsDict = new PyDict(dict)) + using (var clsDict = new PyDict(dict)) { if (clsDict.HasKey("__assembly__") || clsDict.HasKey("__namespace__")) + { return TypeManager.CreateSubType(name, base_type, dict); + } } } // otherwise just create a basic type without reflecting back into the managed side. - IntPtr func = Marshal.ReadIntPtr(Runtime.PyTypeType, - TypeOffset.tp_new); + IntPtr func = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_new); IntPtr type = NativeCall.Call_3(func, tp, args, kw); if (type == IntPtr.Zero) { @@ -115,7 +105,7 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) flags |= TypeFlags.BaseType; flags |= TypeFlags.Subclass; flags |= TypeFlags.HaveGC; - Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); + Util.WriteCLong(type, TypeOffset.tp_flags, flags); TypeManager.CopySlot(base_type, type, TypeOffset.tp_dealloc); @@ -148,12 +138,11 @@ public static void tp_free(IntPtr tp) } - //==================================================================== - // Metatype __call__ implementation. This is needed to ensure correct - // initialization (__init__ support), because the tp_call we inherit - // from PyType_Type won't call __init__ for metatypes it doesnt know. - //==================================================================== - + /// + /// Metatype __call__ implementation. This is needed to ensure correct + /// initialization (__init__ support), because the tp_call we inherit + /// from PyType_Type won't call __init__ for metatypes it doesn't know. + /// public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw) { IntPtr func = Marshal.ReadIntPtr(tp, TypeOffset.tp_new); @@ -168,23 +157,13 @@ public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw) return IntPtr.Zero; } - IntPtr py__init__ = Runtime.PyString_FromString("__init__"); - IntPtr type = Runtime.PyObject_TYPE(obj); - IntPtr init = Runtime._PyType_Lookup(type, py__init__); - Runtime.XDecref(py__init__); + var init = Runtime.PyObject_GetAttrString(obj, "__init__"); Runtime.PyErr_Clear(); if (init != IntPtr.Zero) { - IntPtr bound = Runtime.GetBoundArgTuple(obj, args); - if (bound == IntPtr.Zero) - { - Runtime.XDecref(obj); - return IntPtr.Zero; - } - - IntPtr result = Runtime.PyObject_Call(init, bound, kw); - Runtime.XDecref(bound); + IntPtr result = Runtime.PyObject_Call(init, args, kw); + Runtime.XDecref(init); if (result == IntPtr.Zero) { @@ -199,14 +178,13 @@ public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw) } - //==================================================================== - // Type __setattr__ implementation for reflected types. Note that this - // is slightly different than the standard setattr implementation for - // the normal Python metatype (PyTypeType). We need to look first in - // the type object of a reflected type for a descriptor in order to - // support the right setattr behavior for static fields and properties. - //==================================================================== - + /// + /// Type __setattr__ implementation for reflected types. Note that this + /// is slightly different than the standard setattr implementation for + /// the normal Python metatype (PyTypeType). We need to look first in + /// the type object of a reflected type for a descriptor in order to + /// support the right setattr behavior for static fields and properties. + /// public static int tp_setattro(IntPtr tp, IntPtr name, IntPtr value) { IntPtr descr = Runtime._PyType_Lookup(tp, name); @@ -218,36 +196,32 @@ public static int tp_setattro(IntPtr tp, IntPtr name, IntPtr value) if (dt == Runtime.PyWrapperDescriptorType || dt == Runtime.PyMethodType || typeof(ExtensionType).IsInstanceOfType(GetManagedObject(descr)) - ) + ) { IntPtr fp = Marshal.ReadIntPtr(dt, TypeOffset.tp_descr_set); if (fp != IntPtr.Zero) { - return NativeCall.Impl.Int_Call_3(fp, descr, name, value); - } - else - { - Exceptions.SetError(Exceptions.AttributeError, - "attribute is read-only"); - return -1; + return NativeCall.Int_Call_3(fp, descr, name, value); } + Exceptions.SetError(Exceptions.AttributeError, "attribute is read-only"); + return -1; } } - var res = Runtime.PyObject_GenericSetAttr(tp, name, value); + int res = Runtime.PyObject_GenericSetAttr(tp, name, value); Runtime.PyType_Modified(tp); return res; } - //==================================================================== - // The metatype has to implement [] semantics for generic types, so - // here we just delegate to the generic type def implementation. Its - // own mp_subscript - //==================================================================== + /// + /// The metatype has to implement [] semantics for generic types, so + /// here we just delegate to the generic type def implementation. Its + /// own mp_subscript + /// public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) { - ClassBase cb = GetManagedObject(tp) as ClassBase; + var cb = GetManagedObject(tp) as ClassBase; if (cb != null) { return cb.type_subscript(idx); @@ -255,16 +229,15 @@ public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) return Exceptions.RaiseTypeError("unsubscriptable object"); } - //==================================================================== - // Dealloc implementation. This is called when a Python type generated - // by this metatype is no longer referenced from the Python runtime. - //==================================================================== - + /// + /// Dealloc implementation. This is called when a Python type generated + /// by this metatype is no longer referenced from the Python runtime. + /// public static void tp_dealloc(IntPtr tp) { // Fix this when we dont cheat on the handle for subclasses! - int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags); + var flags = Util.ReadCLong(tp, TypeOffset.tp_flags); if ((flags & TypeFlags.Subclass) == 0) { IntPtr gc = Marshal.ReadIntPtr(tp, TypeOffset.magic()); @@ -281,13 +254,11 @@ public static void tp_dealloc(IntPtr tp) op = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_dealloc); NativeCall.Void_Call_1(op, tp); - - return; } - static IntPtr DoInstanceCheck(IntPtr tp, IntPtr args, bool checkType) + private static IntPtr DoInstanceCheck(IntPtr tp, IntPtr args, bool checkType) { - ClassBase cb = GetManagedObject(tp) as ClassBase; + var cb = GetManagedObject(tp) as ClassBase; if (cb == null) { @@ -295,17 +266,23 @@ static IntPtr DoInstanceCheck(IntPtr tp, IntPtr args, bool checkType) return Runtime.PyFalse; } - using (PyList argsObj = new PyList(args)) + using (var argsObj = new PyList(args)) { if (argsObj.Length() != 1) + { return Exceptions.RaiseTypeError("Invalid parameter count"); + } PyObject arg = argsObj[0]; PyObject otherType; if (checkType) + { otherType = arg; + } else + { otherType = arg.GetPythonType(); + } if (Runtime.PyObject_TYPE(otherType.Handle) != PyCLRMetaType) { @@ -313,7 +290,7 @@ static IntPtr DoInstanceCheck(IntPtr tp, IntPtr args, bool checkType) return Runtime.PyFalse; } - ClassBase otherCb = GetManagedObject(otherType.Handle) as ClassBase; + var otherCb = GetManagedObject(otherType.Handle) as ClassBase; if (otherCb == null) { Runtime.XIncref(Runtime.PyFalse); diff --git a/src/runtime/methodbinder.cs b/src/runtime/methodbinder.cs index c3b3e4a70..f0c58f34f 100644 --- a/src/runtime/methodbinder.cs +++ b/src/runtime/methodbinder.cs @@ -4,13 +4,12 @@ namespace Python.Runtime { - //======================================================================== - // A MethodBinder encapsulates information about a (possibly overloaded) - // managed method, and is responsible for selecting the right method given - // a set of Python arguments. This is also used as a base class for the - // ConstructorBinder, a minor variation used to invoke constructors. - //======================================================================== - + /// + /// A MethodBinder encapsulates information about a (possibly overloaded) + /// managed method, and is responsible for selecting the right method given + /// a set of Python arguments. This is also used as a base class for the + /// ConstructorBinder, a minor variation used to invoke constructors. + /// internal class MethodBinder { public ArrayList list; @@ -20,30 +19,28 @@ internal class MethodBinder internal MethodBinder() { - this.list = new ArrayList(); + list = new ArrayList(); } - internal MethodBinder(MethodInfo mi) : base() + internal MethodBinder(MethodInfo mi) { - this.list = new ArrayList(); - this.list.Add(mi); + list = new ArrayList { mi }; } public int Count { - get { return this.list.Count; } + get { return list.Count; } } internal void AddMethod(MethodBase m) { - this.list.Add(m); + list.Add(m); } - //==================================================================== - // Given a sequence of MethodInfo and a sequence of types, return the - // MethodInfo that matches the signature represented by those types. - //==================================================================== - + /// + /// Given a sequence of MethodInfo and a sequence of types, return the + /// MethodInfo that matches the signature represented by those types. + /// internal static MethodInfo MatchSignature(MethodInfo[] mi, Type[] tp) { if (tp == null) @@ -51,33 +48,32 @@ internal static MethodInfo MatchSignature(MethodInfo[] mi, Type[] tp) return null; } int count = tp.Length; - for (int i = 0; i < mi.Length; i++) + foreach (MethodInfo t in mi) { - ParameterInfo[] pi = mi[i].GetParameters(); + ParameterInfo[] pi = t.GetParameters(); if (pi.Length != count) { continue; } - for (int n = 0; n < pi.Length; n++) + for (var n = 0; n < pi.Length; n++) { if (tp[n] != pi[n].ParameterType) { break; } - if (n == (pi.Length - 1)) + if (n == pi.Length - 1) { - return mi[i]; + return t; } } } return null; } - //==================================================================== - // Given a sequence of MethodInfo and a sequence of type parameters, - // return the MethodInfo that represents the matching closed generic. - //==================================================================== - + /// + /// Given a sequence of MethodInfo and a sequence of type parameters, + /// return the MethodInfo that represents the matching closed generic. + /// internal static MethodInfo MatchParameters(MethodInfo[] mi, Type[] tp) { if (tp == null) @@ -85,63 +81,63 @@ internal static MethodInfo MatchParameters(MethodInfo[] mi, Type[] tp) return null; } int count = tp.Length; - for (int i = 0; i < mi.Length; i++) + foreach (MethodInfo t in mi) { - if (!mi[i].IsGenericMethodDefinition) + if (!t.IsGenericMethodDefinition) { continue; } - Type[] args = mi[i].GetGenericArguments(); + Type[] args = t.GetGenericArguments(); if (args.Length != count) { continue; } - return mi[i].MakeGenericMethod(tp); + return t.MakeGenericMethod(tp); } return null; } - //==================================================================== - // Given a sequence of MethodInfo and two sequences of type parameters, - // return the MethodInfo that matches the signature and the closed generic. - //==================================================================== - + /// + /// Given a sequence of MethodInfo and two sequences of type parameters, + /// return the MethodInfo that matches the signature and the closed generic. + /// internal static MethodInfo MatchSignatureAndParameters(MethodInfo[] mi, Type[] genericTp, Type[] sigTp) { - if ((genericTp == null) || (sigTp == null)) + if (genericTp == null || sigTp == null) { return null; } int genericCount = genericTp.Length; int signatureCount = sigTp.Length; - for (int i = 0; i < mi.Length; i++) + foreach (MethodInfo t in mi) { - if (!mi[i].IsGenericMethodDefinition) + if (!t.IsGenericMethodDefinition) { continue; } - Type[] genericArgs = mi[i].GetGenericArguments(); + Type[] genericArgs = t.GetGenericArguments(); if (genericArgs.Length != genericCount) { continue; } - ParameterInfo[] pi = mi[i].GetParameters(); + ParameterInfo[] pi = t.GetParameters(); if (pi.Length != signatureCount) { continue; } - for (int n = 0; n < pi.Length; n++) + for (var n = 0; n < pi.Length; n++) { if (sigTp[n] != pi[n].ParameterType) { break; } - if (n == (pi.Length - 1)) + if (n == pi.Length - 1) { - MethodInfo match = mi[i]; + MethodInfo match = t; if (match.IsGenericMethodDefinition) { + // FIXME: typeArgs not used Type[] typeArgs = match.GetGenericArguments(); return match.MakeGenericMethod(genericTp); } @@ -153,12 +149,11 @@ internal static MethodInfo MatchSignatureAndParameters(MethodInfo[] mi, Type[] g } - //==================================================================== - // Return the array of MethodInfo for this method. The result array - // is arranged in order of precendence (done lazily to avoid doing it - // at all for methods that are never called). - //==================================================================== - + /// + /// Return the array of MethodInfo for this method. The result array + /// is arranged in order of precedence (done lazily to avoid doing it + /// at all for methods that are never called). + /// internal MethodBase[] GetMethods() { if (!init) @@ -171,19 +166,22 @@ internal MethodBase[] GetMethods() return methods; } - //==================================================================== - // Precedence algorithm largely lifted from jython - the concerns are - // generally the same so we'll start w/this and tweak as necessary. - //==================================================================== - + /// + /// Precedence algorithm largely lifted from Jython - the concerns are + /// generally the same so we'll start with this and tweak as necessary. + /// + /// + /// Based from Jython `org.python.core.ReflectedArgs.precedence` + /// See: https://github.com/jythontools/jython/blob/master/src/org/python/core/ReflectedArgs.java#L192 + /// internal static int GetPrecedence(MethodBase mi) { ParameterInfo[] pi = mi.GetParameters(); int val = mi.IsStatic ? 3000 : 0; int num = pi.Length; - val += (mi.IsGenericMethod ? 1 : 0); - for (int i = 0; i < num; i++) + val += mi.IsGenericMethod ? 1 : 0; + for (var i = 0; i < num; i++) { val += ArgPrecedence(pi[i].ParameterType); } @@ -191,73 +189,103 @@ internal static int GetPrecedence(MethodBase mi) return val; } - //==================================================================== - // Return a precedence value for a particular Type object. - //==================================================================== - + /// + /// Return a precedence value for a particular Type object. + /// internal static int ArgPrecedence(Type t) { - Type objectType = typeof(Object); - if (t == objectType) return 3000; + Type objectType = typeof(object); + if (t == objectType) + { + return 3000; + } TypeCode tc = Type.GetTypeCode(t); - if (tc == TypeCode.Object) return 1; - if (tc == TypeCode.UInt64) return 10; - if (tc == TypeCode.UInt32) return 11; - if (tc == TypeCode.UInt16) return 12; - if (tc == TypeCode.Int64) return 13; - if (tc == TypeCode.Int32) return 14; - if (tc == TypeCode.Int16) return 15; - if (tc == TypeCode.Char) return 16; - if (tc == TypeCode.SByte) return 17; - if (tc == TypeCode.Byte) return 18; - if (tc == TypeCode.Single) return 20; - if (tc == TypeCode.Double) return 21; - if (tc == TypeCode.String) return 30; - if (tc == TypeCode.Boolean) return 40; + // TODO: Clean up + switch (tc) + { + case TypeCode.Object: + return 1; + + case TypeCode.UInt64: + return 10; + + case TypeCode.UInt32: + return 11; + + case TypeCode.UInt16: + return 12; + + case TypeCode.Int64: + return 13; + + case TypeCode.Int32: + return 14; + + case TypeCode.Int16: + return 15; + + case TypeCode.Char: + return 16; + + case TypeCode.SByte: + return 17; + + case TypeCode.Byte: + return 18; + + case TypeCode.Single: + return 20; + + case TypeCode.Double: + return 21; + + case TypeCode.String: + return 30; + + case TypeCode.Boolean: + return 40; + } if (t.IsArray) { Type e = t.GetElementType(); if (e == objectType) + { return 2500; + } return 100 + ArgPrecedence(e); } return 2000; } - //==================================================================== - // Bind the given Python instance and arguments to a particular method - // overload and return a structure that contains the converted Python - // instance, converted arguments and the correct method to call. - //==================================================================== - + /// + /// Bind the given Python instance and arguments to a particular method + /// overload and return a structure that contains the converted Python + /// instance, converted arguments and the correct method to call. + /// internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw) { - return this.Bind(inst, args, kw, null, null); + return Bind(inst, args, kw, null, null); } - internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, - MethodBase info) + internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info) { - return this.Bind(inst, args, kw, info, null); + return Bind(inst, args, kw, info, null); } - internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, - MethodBase info, MethodInfo[] methodinfo) + internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo) { // loop to find match, return invoker w/ or /wo error MethodBase[] _methods = null; int pynargs = Runtime.PyTuple_Size(args); object arg; - bool isGeneric = false; + var isGeneric = false; ArrayList defaultArgList = null; if (info != null) { - _methods = (MethodBase[])Array.CreateInstance( - typeof(MethodBase), 1 - ); + _methods = new MethodBase[1]; _methods.SetValue(info, 0); } else @@ -265,19 +293,18 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, _methods = GetMethods(); } Type clrtype; - for (int i = 0; i < _methods.Length; i++) + // TODO: Clean up + foreach (MethodBase mi in _methods) { - MethodBase mi = _methods[i]; - if (mi.IsGenericMethod) { isGeneric = true; } ParameterInfo[] pi = mi.GetParameters(); int clrnargs = pi.Length; - bool match = false; + var match = false; int arrayStart = -1; - int outs = 0; + var outs = 0; if (pynargs == clrnargs) { @@ -290,24 +317,28 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, for (int v = pynargs; v < clrnargs; v++) { if (pi[v].DefaultValue == DBNull.Value) + { match = false; + } else - defaultArgList.Add((object)pi[v].DefaultValue); + { + defaultArgList.Add(pi[v].DefaultValue); + } } } - else if ((pynargs > clrnargs) && (clrnargs > 0) && + else if (pynargs > clrnargs && clrnargs > 0 && Attribute.IsDefined(pi[clrnargs - 1], typeof(ParamArrayAttribute))) { - // This is a spam(params object[] egg) style method + // This is a `foo(params object[] bar)` style method match = true; arrayStart = clrnargs - 1; } if (match) { - Object[] margs = new Object[clrnargs]; + var margs = new object[clrnargs]; - for (int n = 0; n < clrnargs; n++) + for (var n = 0; n < clrnargs; n++) { IntPtr op; if (n < pynargs) @@ -343,8 +374,8 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, if (clrtype != null) { - bool typematch = false; - if (pi[n].ParameterType != clrtype) + var typematch = false; + if ((pi[n].ParameterType != typeof(object)) && (pi[n].ParameterType != clrtype)) { IntPtr pytype = Converter.GetPythonTypeByAlias(pi[n].ParameterType); pyoptype = Runtime.PyObject_Type(op); @@ -412,7 +443,9 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, else { if (defaultArgList != null) + { margs[n] = defaultArgList[n - pynargs]; + } } } @@ -421,13 +454,13 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, continue; } - Object target = null; - if ((!mi.IsStatic) && (inst != IntPtr.Zero)) + object target = null; + if (!mi.IsStatic && inst != IntPtr.Zero) { //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst); // InvalidCastException: Unable to cast object of type // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject' - CLRObject co = ManagedType.GetManagedObject(inst) as CLRObject; + var co = ManagedType.GetManagedObject(inst) as CLRObject; // Sanity check: this ensures a graceful exit if someone does // something intentionally wrong like call a non-static method @@ -447,10 +480,10 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, // is a generic method and info is null. That happens when a generic // method was not called using the [] syntax. Let's introspect the // type of the arguments and use it to construct the correct method. - if (isGeneric && (info == null) && (methodinfo != null)) + if (isGeneric && info == null && methodinfo != null) { Type[] types = Runtime.PythonArgsToTypeArray(args, true); - MethodInfo mi = MethodBinder.MatchParameters(methodinfo, types); + MethodInfo mi = MatchParameters(methodinfo, types); return Bind(inst, args, kw, mi, null); } return null; @@ -458,27 +491,23 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw) { - return this.Invoke(inst, args, kw, null, null); + return Invoke(inst, args, kw, null, null); } - internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, - MethodBase info) + internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info) { - return this.Invoke(inst, args, kw, info, null); + return Invoke(inst, args, kw, info, null); } - internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, - MethodBase info, MethodInfo[] methodinfo) + internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, MethodInfo[] methodinfo) { - Binding binding = this.Bind(inst, args, kw, info, methodinfo); - Object result; + Binding binding = Bind(inst, args, kw, info, methodinfo); + object result; IntPtr ts = IntPtr.Zero; if (binding == null) { - Exceptions.SetError(Exceptions.TypeError, - "No method matches given arguments" - ); + Exceptions.SetError(Exceptions.TypeError, "No method matches given arguments"); return IntPtr.Zero; } @@ -489,11 +518,7 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, try { - result = binding.info.Invoke(binding.inst, - BindingFlags.Default, - null, - binding.args, - null); + result = binding.info.Invoke(binding.inst, BindingFlags.Default, null, binding.args, null); } catch (Exception e) { @@ -520,9 +545,9 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, // we return the out parameter as the result to Python (for // code compatibility with ironpython). - MethodInfo mi = (MethodInfo)binding.info; + var mi = (MethodInfo)binding.info; - if ((binding.outs == 1) && (mi.ReturnType == typeof(void))) + if (binding.outs == 1 && mi.ReturnType == typeof(void)) { } @@ -530,14 +555,14 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, { ParameterInfo[] pi = mi.GetParameters(); int c = pi.Length; - int n = 0; + var n = 0; IntPtr t = Runtime.PyTuple_New(binding.outs + 1); IntPtr v = Converter.ToPython(result, mi.ReturnType); Runtime.PyTuple_SetItem(t, n, v); n++; - for (int i = 0; i < c; i++) + for (var i = 0; i < c; i++) { Type pt = pi[i].ParameterType; if (pi[i].IsOut || pt.IsByRef) @@ -548,7 +573,7 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, } } - if ((binding.outs == 1) && (mi.ReturnType == typeof(void))) + if (binding.outs == 1 && mi.ReturnType == typeof(void)) { v = Runtime.PyTuple_GetItem(t, 1); Runtime.XIncref(v); @@ -564,38 +589,41 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, } - //======================================================================== - // Utility class to sort method info by parameter type precedence. - //======================================================================== - + /// + /// Utility class to sort method info by parameter type precedence. + /// internal class MethodSorter : IComparer { - int IComparer.Compare(Object m1, Object m2) + int IComparer.Compare(object m1, object m2) { int p1 = MethodBinder.GetPrecedence((MethodBase)m1); int p2 = MethodBinder.GetPrecedence((MethodBase)m2); - if (p1 < p2) return -1; - if (p1 > p2) return 1; + if (p1 < p2) + { + return -1; + } + if (p1 > p2) + { + return 1; + } return 0; } } - //======================================================================== - // A Binding is a utility instance that bundles together a MethodInfo - // representing a method to call, a (possibly null) target instance for - // the call, and the arguments for the call (all as managed values). - //======================================================================== - + /// + /// A Binding is a utility instance that bundles together a MethodInfo + /// representing a method to call, a (possibly null) target instance for + /// the call, and the arguments for the call (all as managed values). + /// internal class Binding { public MethodBase info; - public Object[] args; - public Object inst; + public object[] args; + public object inst; public int outs; - internal Binding(MethodBase info, Object inst, Object[] args, - int outs) + internal Binding(MethodBase info, object inst, object[] args, int outs) { this.info = info; this.inst = inst; @@ -603,4 +631,4 @@ internal Binding(MethodBase info, Object inst, Object[] args, this.outs = outs; } } -} \ No newline at end of file +} diff --git a/src/runtime/methodbinding.cs b/src/runtime/methodbinding.cs index d8fec069c..07090a92c 100644 --- a/src/runtime/methodbinding.cs +++ b/src/runtime/methodbinding.cs @@ -1,15 +1,14 @@ using System; -using System.Reflection; using System.Collections.Generic; +using System.Reflection; namespace Python.Runtime { - //======================================================================== - // Implements a Python binding type for CLR methods. These work much like - // standard Python method bindings, but the same type is used to bind - // both static and instance methods. - //======================================================================== - + /// + /// Implements a Python binding type for CLR methods. These work much like + /// standard Python method bindings, but the same type is used to bind + /// both static and instance methods. + /// internal class MethodBinding : ExtensionType { internal MethodInfo info; @@ -17,14 +16,16 @@ internal class MethodBinding : ExtensionType internal IntPtr target; internal IntPtr targetType; - public MethodBinding(MethodObject m, IntPtr target, IntPtr targetType) : base() + public MethodBinding(MethodObject m, IntPtr target, IntPtr targetType) { Runtime.XIncref(target); this.target = target; Runtime.XIncref(targetType); if (targetType == IntPtr.Zero) + { targetType = Runtime.PyObject_Type(target); + } this.targetType = targetType; this.info = null; @@ -35,13 +36,12 @@ public MethodBinding(MethodObject m, IntPtr target) : this(m, target, IntPtr.Zer { } - //==================================================================== - // Implement binding of generic methods using the subscript syntax []. - //==================================================================== - + /// + /// Implement binding of generic methods using the subscript syntax []. + /// public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) { - MethodBinding self = (MethodBinding)GetManagedObject(tp); + var self = (MethodBinding)GetManagedObject(tp); Type[] types = Runtime.PythonArgsToTypeArray(idx); if (types == null) @@ -52,24 +52,21 @@ public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) MethodInfo mi = MethodBinder.MatchParameters(self.m.info, types); if (mi == null) { - string e = "No match found for given type params"; - return Exceptions.RaiseTypeError(e); + return Exceptions.RaiseTypeError("No match found for given type params"); } - MethodBinding mb = new MethodBinding(self.m, self.target); - mb.info = mi; + var mb = new MethodBinding(self.m, self.target) { info = mi }; Runtime.XIncref(mb.pyHandle); return mb.pyHandle; } - //==================================================================== - // MethodBinding __getattribute__ implementation. - //==================================================================== - + /// + /// MethodBinding __getattribute__ implementation. + /// public static IntPtr tp_getattro(IntPtr ob, IntPtr key) { - MethodBinding self = (MethodBinding)GetManagedObject(ob); + var self = (MethodBinding)GetManagedObject(ob); if (!Runtime.PyString_Check(key)) { @@ -78,32 +75,30 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key) } string name = Runtime.GetManagedString(key); - if (name == "__doc__") - { - IntPtr doc = self.m.GetDocString(); - Runtime.XIncref(doc); - return doc; - } - - // XXX deprecate __overloads__ soon... - if (name == "__overloads__" || name == "Overloads") + switch (name) { - OverloadMapper om = new OverloadMapper(self.m, self.target); - Runtime.XIncref(om.pyHandle); - return om.pyHandle; + case "__doc__": + IntPtr doc = self.m.GetDocString(); + Runtime.XIncref(doc); + return doc; + // FIXME: deprecate __overloads__ soon... + case "__overloads__": + case "Overloads": + var om = new OverloadMapper(self.m, self.target); + Runtime.XIncref(om.pyHandle); + return om.pyHandle; + default: + return Runtime.PyObject_GenericGetAttr(ob, key); } - - return Runtime.PyObject_GenericGetAttr(ob, key); } - //==================================================================== - // MethodBinding __call__ implementation. - //==================================================================== - + /// + /// MethodBinding __call__ implementation. + /// public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { - MethodBinding self = (MethodBinding)GetManagedObject(ob); + var self = (MethodBinding)GetManagedObject(ob); // This works around a situation where the wrong generic method is picked, // for example this method in the tests: string Overloaded(int arg1, int arg2, string arg3) @@ -111,13 +106,16 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { if (self.info.IsGenericMethod) { - int len = Runtime.PyTuple_Size(args); + int len = Runtime.PyTuple_Size(args); //FIXME: Never used Type[] sigTp = Runtime.PythonArgsToTypeArray(args, true); if (sigTp != null) { Type[] genericTp = self.info.GetGenericArguments(); MethodInfo betterMatch = MethodBinder.MatchSignatureAndParameters(self.m.info, genericTp, sigTp); - if (betterMatch != null) self.info = betterMatch; + if (betterMatch != null) + { + self.info = betterMatch; + } } } } @@ -126,12 +124,12 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) // as the first argument. Note that this is not supported if any // of the overloads are static since we can't know if the intent // was to call the static method or the unbound instance method. - List disposeList = new List(); + var disposeList = new List(); try { IntPtr target = self.target; - if ((target == IntPtr.Zero) && (!self.m.IsStatic())) + if (target == IntPtr.Zero && !self.m.IsStatic()) { int len = Runtime.PyTuple_Size(args); if (len < 1) @@ -153,19 +151,21 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) IntPtr superType = IntPtr.Zero; if (Runtime.PyObject_TYPE(target) != self.targetType) { - CLRObject inst = CLRObject.GetManagedObject(target) as CLRObject; - if (inst != null && (inst.inst as IPythonDerivedType) != null) + var inst = GetManagedObject(target) as CLRObject; + if (inst?.inst is IPythonDerivedType) { - ClassBase baseType = GetManagedObject(self.targetType) as ClassBase; + var baseType = GetManagedObject(self.targetType) as ClassBase; if (baseType != null) { string baseMethodName = "_" + baseType.type.Name + "__" + self.m.name; IntPtr baseMethod = Runtime.PyObject_GetAttrString(target, baseMethodName); if (baseMethod != IntPtr.Zero) { - MethodBinding baseSelf = GetManagedObject(baseMethod) as MethodBinding; + var baseSelf = GetManagedObject(baseMethod) as MethodBinding; if (baseSelf != null) + { self = baseSelf; + } Runtime.XDecref(baseMethod); } else @@ -181,18 +181,19 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) finally { foreach (IntPtr ptr in disposeList) + { Runtime.XDecref(ptr); + } } } - //==================================================================== - // MethodBinding __hash__ implementation. - //==================================================================== - + /// + /// MethodBinding __hash__ implementation. + /// public static IntPtr tp_hash(IntPtr ob) { - MethodBinding self = (MethodBinding)GetManagedObject(ob); + var self = (MethodBinding)GetManagedObject(ob); long x = 0; long y = 0; @@ -221,28 +222,26 @@ public static IntPtr tp_hash(IntPtr ob) return new IntPtr(x); } - //==================================================================== - // MethodBinding __repr__ implementation. - //==================================================================== - + /// + /// MethodBinding __repr__ implementation. + /// public static IntPtr tp_repr(IntPtr ob) { - MethodBinding self = (MethodBinding)GetManagedObject(ob); - string type = (self.target == IntPtr.Zero) ? "unbound" : "bound"; - string s = String.Format("<{0} method '{1}'>", type, self.m.name); - return Runtime.PyString_FromStringAndSize(s, s.Length); + var self = (MethodBinding)GetManagedObject(ob); + string type = self.target == IntPtr.Zero ? "unbound" : "bound"; + string name = self.m.name; + return Runtime.PyString_FromString($"<{type} method '{name}'>"); } - //==================================================================== - // MethodBinding dealloc implementation. - //==================================================================== - - public static new void tp_dealloc(IntPtr ob) + /// + /// MethodBinding dealloc implementation. + /// + public new static void tp_dealloc(IntPtr ob) { - MethodBinding self = (MethodBinding)GetManagedObject(ob); + var self = (MethodBinding)GetManagedObject(ob); Runtime.XDecref(self.target); Runtime.XDecref(self.targetType); - ExtensionType.FinalizeObject(self); + FinalizeObject(self); } } -} \ No newline at end of file +} diff --git a/src/runtime/methodobject.cs b/src/runtime/methodobject.cs index 20f757d58..8df9c8029 100644 --- a/src/runtime/methodobject.cs +++ b/src/runtime/methodobject.cs @@ -1,15 +1,15 @@ using System; -using System.Collections; using System.Reflection; namespace Python.Runtime { - //======================================================================== - // Implements a Python type that represents a CLR method. Method objects - // support a subscript syntax [] to allow explicit overload selection. - //======================================================================== - // TODO: ForbidPythonThreadsAttribute per method info - + /// + /// Implements a Python type that represents a CLR method. Method objects + /// support a subscript syntax [] to allow explicit overload selection. + /// + /// + /// TODO: ForbidPythonThreadsAttribute per method info + /// internal class MethodObject : ExtensionType { internal MethodInfo[] info; @@ -20,12 +20,12 @@ internal class MethodObject : ExtensionType internal IntPtr doc; internal Type type; - public MethodObject(Type type, string name, MethodInfo[] info) : base() + public MethodObject(Type type, string name, MethodInfo[] info) { _MethodObject(type, name, info); } - public MethodObject(Type type, string name, MethodInfo[] info, bool allow_threads) : base() + public MethodObject(Type type, string name, MethodInfo[] info, bool allow_threads) { _MethodObject(type, name, info); binder.allow_threads = allow_threads; @@ -37,9 +37,8 @@ private void _MethodObject(Type type, string name, MethodInfo[] info) this.name = name; this.info = info; binder = new MethodBinder(); - for (int i = 0; i < info.Length; i++) + foreach (MethodInfo item in info) { - MethodInfo item = (MethodInfo)info[i]; binder.AddMethod(item); if (item.IsStatic) { @@ -50,40 +49,40 @@ private void _MethodObject(Type type, string name, MethodInfo[] info) public virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw) { - return this.Invoke(inst, args, kw, null); + return Invoke(inst, args, kw, null); } - public virtual IntPtr Invoke(IntPtr target, IntPtr args, IntPtr kw, - MethodBase info) + public virtual IntPtr Invoke(IntPtr target, IntPtr args, IntPtr kw, MethodBase info) { return binder.Invoke(target, args, kw, info, this.info); } - //==================================================================== - // Helper to get docstrings from reflected method / param info. - //==================================================================== - + /// + /// Helper to get docstrings from reflected method / param info. + /// internal IntPtr GetDocString() { if (doc != IntPtr.Zero) { return doc; } - string str = ""; + var str = ""; Type marker = typeof(DocStringAttribute); MethodBase[] methods = binder.GetMethods(); foreach (MethodBase method in methods) { if (str.Length > 0) + { str += Environment.NewLine; - Attribute[] attrs = (Attribute[])method.GetCustomAttributes(marker, false); + } + var attrs = (Attribute[])method.GetCustomAttributes(marker, false); if (attrs.Length == 0) { str += method.ToString(); } else { - DocStringAttribute attr = (DocStringAttribute)attrs[0]; + var attr = (DocStringAttribute)attrs[0]; str += attr.DocString; } } @@ -92,31 +91,30 @@ internal IntPtr GetDocString() } - //==================================================================== - // This is a little tricky: a class can actually have a static method - // and instance methods all with the same name. That makes it tough - // to support calling a method 'unbound' (passing the instance as the - // first argument), because in this case we can't know whether to call - // the instance method unbound or call the static method. - // - // The rule we is that if there are both instance and static methods - // with the same name, then we always call the static method. So this - // method returns true if any of the methods that are represented by - // the descriptor are static methods (called by MethodBinding). - //==================================================================== - + /// + /// This is a little tricky: a class can actually have a static method + /// and instance methods all with the same name. That makes it tough + /// to support calling a method 'unbound' (passing the instance as the + /// first argument), because in this case we can't know whether to call + /// the instance method unbound or call the static method. + /// + /// + /// The rule we is that if there are both instance and static methods + /// with the same name, then we always call the static method. So this + /// method returns true if any of the methods that are represented by + /// the descriptor are static methods (called by MethodBinding). + /// internal bool IsStatic() { - return this.is_static; + return is_static; } - //==================================================================== - // Descriptor __getattribute__ implementation. - //==================================================================== - + /// + /// Descriptor __getattribute__ implementation. + /// public static IntPtr tp_getattro(IntPtr ob, IntPtr key) { - MethodObject self = (MethodObject)GetManagedObject(ob); + var self = (MethodObject)GetManagedObject(ob); if (!Runtime.PyString_Check(key)) { @@ -134,14 +132,13 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key) return Runtime.PyObject_GenericGetAttr(ob, key); } - //==================================================================== - // Descriptor __get__ implementation. Accessing a CLR method returns - // a "bound" method similar to a Python bound method. - //==================================================================== - + /// + /// Descriptor __get__ implementation. Accessing a CLR method returns + /// a "bound" method similar to a Python bound method. + /// public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { - MethodObject self = (MethodObject)GetManagedObject(ds); + var self = (MethodObject)GetManagedObject(ds); MethodBinding binding; // If the method is accessed through its type (rather than via @@ -169,11 +166,11 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) // this descriptor was defined on then it will be because the base class method // is being called via super(Derived, self).method(...). // In which case create a MethodBinding bound to the base class. - CLRObject obj = GetManagedObject(ob) as CLRObject; + var obj = GetManagedObject(ob) as CLRObject; if (obj != null && obj.inst.GetType() != self.type && obj.inst is IPythonDerivedType - && self.type.IsAssignableFrom(obj.inst.GetType())) + && self.type.IsInstanceOfType(obj.inst)) { ClassBase basecls = ClassManager.GetClass(self.type); binding = new MethodBinding(self, ob, basecls.pyHandle); @@ -184,24 +181,21 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) return binding.pyHandle; } - //==================================================================== - // Descriptor __repr__ implementation. - //==================================================================== - + /// + /// Descriptor __repr__ implementation. + /// public static IntPtr tp_repr(IntPtr ob) { - MethodObject self = (MethodObject)GetManagedObject(ob); - string s = String.Format("", self.name); - return Runtime.PyString_FromStringAndSize(s, s.Length); + var self = (MethodObject)GetManagedObject(ob); + return Runtime.PyString_FromString($""); } - //==================================================================== - // Descriptor dealloc implementation. - //==================================================================== - - public static new void tp_dealloc(IntPtr ob) + /// + /// Descriptor dealloc implementation. + /// + public new static void tp_dealloc(IntPtr ob) { - MethodObject self = (MethodObject)GetManagedObject(ob); + var self = (MethodObject)GetManagedObject(ob); Runtime.XDecref(self.doc); if (self.unbound != null) { @@ -210,4 +204,4 @@ public static IntPtr tp_repr(IntPtr ob) ExtensionType.FinalizeObject(self); } } -} \ No newline at end of file +} diff --git a/src/runtime/methodwrapper.cs b/src/runtime/methodwrapper.cs index 53c0a3cc9..2f3ce3ef2 100644 --- a/src/runtime/methodwrapper.cs +++ b/src/runtime/methodwrapper.cs @@ -1,6 +1,4 @@ using System; -using System.Collections; -using System.Runtime.InteropServices; namespace Python.Runtime { @@ -24,7 +22,7 @@ public MethodWrapper(Type type, string name, string funcType = null) // Allocate and initialize a PyMethodDef structure to represent // the managed method, then create a PyCFunction. - mdef = Runtime.PyMem_Malloc(4*IntPtr.Size); + mdef = Runtime.PyMem_Malloc(4 * IntPtr.Size); TypeManager.WriteMethodDef(mdef, name, fp, 0x0003); ptr = Runtime.PyCFunction_NewEx(mdef, IntPtr.Zero, IntPtr.Zero); } @@ -34,4 +32,4 @@ public IntPtr Call(IntPtr args, IntPtr kw) return Runtime.PyCFunction_Call(ptr, args, kw); } } -} \ No newline at end of file +} diff --git a/src/runtime/modulefunctionobject.cs b/src/runtime/modulefunctionobject.cs index efd0384c4..8f8692af9 100644 --- a/src/runtime/modulefunctionobject.cs +++ b/src/runtime/modulefunctionobject.cs @@ -1,5 +1,5 @@ using System; -using System.Collections; +using System.Linq; using System.Reflection; namespace Python.Runtime @@ -12,35 +12,28 @@ internal class ModuleFunctionObject : MethodObject public ModuleFunctionObject(Type type, string name, MethodInfo[] info, bool allow_threads) : base(type, name, info, allow_threads) { - for (int i = 0; i < info.Length; i++) + if (info.Any(item => !item.IsStatic)) { - MethodInfo item = (MethodInfo)info[i]; - if (!item.IsStatic) - { - throw new Exception("Module function must be static."); - } + throw new Exception("Module function must be static."); } } - //==================================================================== - // __call__ implementation. - //==================================================================== - + /// + /// __call__ implementation. + /// public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { - ModuleFunctionObject self = (ModuleFunctionObject)GetManagedObject(ob); + var self = (ModuleFunctionObject)GetManagedObject(ob); return self.Invoke(ob, args, kw); } - //==================================================================== - // __repr__ implementation. - //==================================================================== - - public static new IntPtr tp_repr(IntPtr ob) + /// + /// __repr__ implementation. + /// + public new static IntPtr tp_repr(IntPtr ob) { - ModuleFunctionObject self = (ModuleFunctionObject)GetManagedObject(ob); - string s = String.Format("", self.name); - return Runtime.PyString_FromStringAndSize(s, s.Length); + var self = (ModuleFunctionObject)GetManagedObject(ob); + return Runtime.PyString_FromString($""); } } -} \ No newline at end of file +} diff --git a/src/runtime/moduleobject.cs b/src/runtime/moduleobject.cs index 87e3ed2f1..e683026f9 100644 --- a/src/runtime/moduleobject.cs +++ b/src/runtime/moduleobject.cs @@ -1,27 +1,25 @@ using System; -using System.Collections.Specialized; -using System.Runtime.InteropServices; using System.Collections.Generic; -using System.Collections; +using System.IO; using System.Reflection; +using System.Runtime.InteropServices; namespace Python.Runtime { - //======================================================================== - // Implements a Python type that provides access to CLR namespaces. The - // type behaves like a Python module, and can contain other sub-modules. - //======================================================================== - + /// + /// Implements a Python type that provides access to CLR namespaces. The + /// type behaves like a Python module, and can contain other sub-modules. + /// internal class ModuleObject : ExtensionType { - Dictionary cache; + private Dictionary cache; internal string moduleName; internal IntPtr dict; protected string _namespace; - public ModuleObject(string name) : base() + public ModuleObject(string name) { - if (name == String.Empty) + if (name == string.Empty) { throw new ArgumentException("Name must not be empty!"); } @@ -31,8 +29,8 @@ public ModuleObject(string name) : base() // Use the filename from any of the assemblies just so there's something for // anything that expects __file__ to be set. - string filename = "unknown"; - string docstring = "Namespace containing types from the following assemblies:\n\n"; + var filename = "unknown"; + var docstring = "Namespace containing types from the following assemblies:\n\n"; foreach (Assembly a in AssemblyManager.GetAssemblies(name)) { if (!a.IsDynamic && a.Location != null) @@ -46,7 +44,7 @@ public ModuleObject(string name) : base() IntPtr pyname = Runtime.PyString_FromString(moduleName); IntPtr pyfilename = Runtime.PyString_FromString(filename); IntPtr pydocstring = Runtime.PyString_FromString(docstring); - IntPtr pycls = TypeManager.GetTypeHandle(this.GetType()); + IntPtr pycls = TypeManager.GetTypeHandle(GetType()); Runtime.PyDict_SetItemString(dict, "__name__", pyname); Runtime.PyDict_SetItemString(dict, "__file__", pyfilename); Runtime.PyDict_SetItemString(dict, "__doc__", pydocstring); @@ -55,23 +53,22 @@ public ModuleObject(string name) : base() Runtime.XDecref(pyfilename); Runtime.XDecref(pydocstring); - Marshal.WriteIntPtr(this.pyHandle, ObjectOffset.DictOffset(this.pyHandle), dict); + Marshal.WriteIntPtr(pyHandle, ObjectOffset.DictOffset(pyHandle), dict); InitializeModuleMembers(); } - //=================================================================== - // Returns a ClassBase object representing a type that appears in - // this module's namespace or a ModuleObject representing a child - // namespace (or null if the name is not found). This method does - // not increment the Python refcount of the returned object. - //=================================================================== - + /// + /// Returns a ClassBase object representing a type that appears in + /// this module's namespace or a ModuleObject representing a child + /// namespace (or null if the name is not found). This method does + /// not increment the Python refcount of the returned object. + /// public ManagedType GetAttribute(string name, bool guess) { ManagedType cached = null; - this.cache.TryGetValue(name, out cached); + cache.TryGetValue(name, out cached); if (cached != null) { return cached; @@ -91,25 +88,23 @@ public ManagedType GetAttribute(string name, bool guess) // return null; //} - string qname = (_namespace == String.Empty) + string qname = _namespace == string.Empty ? name : _namespace + "." + name; // If the fully-qualified name of the requested attribute is // a namespace exported by a currently loaded assembly, return // a new ModuleObject representing that namespace. - if (AssemblyManager.IsValidNamespace(qname)) { m = new ModuleObject(qname); StoreAttribute(name, m); - return (ManagedType)m; + return m; } // Look for a type in the current namespace. Note that this // includes types, delegates, enums, interfaces and structs. // Only public namespace members are exposed to Python. - type = AssemblyManager.LookupType(qname); if (type != null) { @@ -119,7 +114,7 @@ public ManagedType GetAttribute(string name, bool guess) } c = ClassManager.GetClass(type); StoreAttribute(name, c); - return (ManagedType)c; + return c; } // This is a little repetitive, but it ensures that the right @@ -133,7 +128,7 @@ public ManagedType GetAttribute(string name, bool guess) { m = new ModuleObject(qname); StoreAttribute(name, m); - return (ManagedType)m; + return m; } type = AssemblyManager.LookupType(qname); @@ -145,7 +140,7 @@ public ManagedType GetAttribute(string name, bool guess) } c = ClassManager.GetClass(type); StoreAttribute(name, c); - return (ManagedType)c; + return c; } } @@ -156,11 +151,9 @@ public ManagedType GetAttribute(string name, bool guess) // future assembly load could contribute a non-generic type to // the current namespace with the given basename, but unlikely // enough to complicate the implementation for now. - if (guess) { - string gname = GenericUtil.GenericNameForBaseName( - _namespace, name); + string gname = GenericUtil.GenericNameForBaseName(_namespace, name); if (gname != null) { ManagedType o = GetAttribute(gname, false); @@ -176,10 +169,9 @@ public ManagedType GetAttribute(string name, bool guess) } - //=================================================================== - // Stores an attribute in the instance dict for future lookups. - //=================================================================== - + /// + /// Stores an attribute in the instance dict for future lookups. + /// private void StoreAttribute(string name, ManagedType ob) { Runtime.PyDict_SetItemString(dict, name, ob.pyHandle); @@ -187,21 +179,20 @@ private void StoreAttribute(string name, ManagedType ob) } - //=================================================================== - // Preloads all currently-known names for the module namespace. This - // can be called multiple times, to add names from assemblies that - // may have been loaded since the last call to the method. - //=================================================================== - + /// + /// Preloads all currently-known names for the module namespace. This + /// can be called multiple times, to add names from assemblies that + /// may have been loaded since the last call to the method. + /// public void LoadNames() { ManagedType m = null; foreach (string name in AssemblyManager.GetNames(_namespace)) { - this.cache.TryGetValue(name, out m); + cache.TryGetValue(name, out m); if (m == null) { - ManagedType attr = this.GetAttribute(name, true); + ManagedType attr = GetAttribute(name, true); } } } @@ -214,38 +205,36 @@ internal void InitializeModuleMembers() Type funcmarker = typeof(ModuleFunctionAttribute); Type propmarker = typeof(ModulePropertyAttribute); Type ftmarker = typeof(ForbidPythonThreadsAttribute); - Type type = this.GetType(); + Type type = GetType(); BindingFlags flags = BindingFlags.Public | BindingFlags.Static; while (type != null) { MethodInfo[] methods = type.GetMethods(flags); - for (int i = 0; i < methods.Length; i++) + foreach (MethodInfo method in methods) { - MethodInfo method = methods[i]; object[] attrs = method.GetCustomAttributes(funcmarker, false); object[] forbid = method.GetCustomAttributes(ftmarker, false); - bool allow_threads = (forbid.Length == 0); + bool allow_threads = forbid.Length == 0; if (attrs.Length > 0) { string name = method.Name; - MethodInfo[] mi = new MethodInfo[1]; + var mi = new MethodInfo[1]; mi[0] = method; - ModuleFunctionObject m = new ModuleFunctionObject(type, name, mi, allow_threads); + var m = new ModuleFunctionObject(type, name, mi, allow_threads); StoreAttribute(name, m); } } PropertyInfo[] properties = type.GetProperties(); - for (int i = 0; i < properties.Length; i++) + foreach (PropertyInfo property in properties) { - PropertyInfo property = properties[i]; object[] attrs = property.GetCustomAttributes(propmarker, false); if (attrs.Length > 0) { string name = property.Name; - ModulePropertyObject p = new ModulePropertyObject(property); + var p = new ModulePropertyObject(property); StoreAttribute(name, p); } } @@ -254,16 +243,15 @@ internal void InitializeModuleMembers() } - //==================================================================== - // ModuleObject __getattribute__ implementation. Module attributes - // are always either classes or sub-modules representing subordinate - // namespaces. CLR modules implement a lazy pattern - the sub-modules - // and classes are created when accessed and cached for future use. - //==================================================================== - + /// + /// ModuleObject __getattribute__ implementation. Module attributes + /// are always either classes or sub-modules representing subordinate + /// namespaces. CLR modules implement a lazy pattern - the sub-modules + /// and classes are created when accessed and cached for future use. + /// public static IntPtr tp_getattro(IntPtr ob, IntPtr key) { - ModuleObject self = (ModuleObject)GetManagedObject(ob); + var self = (ModuleObject)GetManagedObject(ob); if (!Runtime.PyString_Check(key)) { @@ -297,15 +285,13 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key) return attr.pyHandle; } - //==================================================================== - // ModuleObject __repr__ implementation. - //==================================================================== - + /// + /// ModuleObject __repr__ implementation. + /// public static IntPtr tp_repr(IntPtr ob) { - ModuleObject self = (ModuleObject)GetManagedObject(ob); - string s = String.Format("", self.moduleName); - return Runtime.PyString_FromString(s); + var self = (ModuleObject)GetManagedObject(ob); + return Runtime.PyString_FromString($""); } } @@ -325,7 +311,7 @@ internal class CLRModule : ModuleObject public CLRModule() : base("clr") { - _namespace = String.Empty; + _namespace = string.Empty; // This hackery is required in order to allow a plain Python to // import the managed runtime via the CLR bootstrapper module. @@ -333,7 +319,7 @@ public CLRModule() : base("clr") // import requires the module to pass PyModule_Check. :( if (!hacked) { - IntPtr type = this.tpHandle; + IntPtr type = tpHandle; IntPtr mro = Marshal.ReadIntPtr(type, TypeOffset.tp_mro); IntPtr ext = Runtime.ExtendTuple(mro, Runtime.PyModuleType); Marshal.WriteIntPtr(type, TypeOffset.tp_mro, ext); @@ -364,34 +350,34 @@ internal void InitializePreload() } } - [ModuleFunctionAttribute()] + [ModuleFunction] public static bool getPreload() { return preload; } - [ModuleFunctionAttribute()] + [ModuleFunction] public static void setPreload(bool preloadFlag) { preload = preloadFlag; } - //[ModulePropertyAttribute] + //[ModuleProperty] public static bool SuppressDocs { get { return _SuppressDocs; } set { _SuppressDocs = value; } } - //[ModulePropertyAttribute] + //[ModuleProperty] public static bool SuppressOverloads { get { return _SuppressOverloads; } set { _SuppressOverloads = value; } } - [ModuleFunctionAttribute()] - [ForbidPythonThreadsAttribute()] + [ModuleFunction] + [ForbidPythonThreads] public static Assembly AddReference(string name) { AssemblyManager.UpdatePath(); @@ -411,40 +397,60 @@ public static Assembly AddReference(string name) } if (assembly == null) { - string msg = String.Format("Unable to find assembly '{0}'.", name); - throw new System.IO.FileNotFoundException(msg); + throw new FileNotFoundException($"Unable to find assembly '{name}'."); } return assembly; } - [ModuleFunctionAttribute()] - [ForbidPythonThreadsAttribute()] + /// + /// Get a Type instance for a class object. + /// clr.GetClrType(IComparable) gives you the Type for IComparable, + /// that you can e.g. perform reflection on. Similar to typeof(IComparable) in C# + /// or clr.GetClrType(IComparable) in IronPython. + /// + /// + /// + /// The Type object + + [ModuleFunction] + [ForbidPythonThreads] + public static Type GetClrType(Type type) + { + return type; + } + + [ModuleFunction] + [ForbidPythonThreads] public static string FindAssembly(string name) { AssemblyManager.UpdatePath(); return AssemblyManager.FindAssembly(name); } - [ModuleFunctionAttribute()] - public static String[] ListAssemblies(bool verbose) + [ModuleFunction] + public static string[] ListAssemblies(bool verbose) { AssemblyName[] assnames = AssemblyManager.ListAssemblies(); - String[] names = new String[assnames.Length]; - for (int i = 0; i < assnames.Length; i++) + var names = new string[assnames.Length]; + for (var i = 0; i < assnames.Length; i++) { if (verbose) + { names[i] = assnames[i].FullName; + } else + { names[i] = assnames[i].Name; + } } return names; } - [ModuleFunctionAttribute()] + [ModuleFunction] public static int _AtExit() { return Runtime.AtExit(); } } -} \ No newline at end of file +} diff --git a/src/runtime/modulepropertyobject.cs b/src/runtime/modulepropertyobject.cs index 1f67f89ec..8f5edb6ef 100644 --- a/src/runtime/modulepropertyobject.cs +++ b/src/runtime/modulepropertyobject.cs @@ -1,7 +1,5 @@ using System; -using System.Collections; using System.Reflection; -using System.Security.Permissions; namespace Python.Runtime { @@ -10,9 +8,9 @@ namespace Python.Runtime /// internal class ModulePropertyObject : ExtensionType { - public ModulePropertyObject(PropertyInfo md) : base() + public ModulePropertyObject(PropertyInfo md) { throw new NotImplementedException("ModulePropertyObject"); } } -} \ No newline at end of file +} diff --git a/src/runtime/monosupport.cs b/src/runtime/monosupport.cs deleted file mode 100644 index 52c2921da..000000000 --- a/src/runtime/monosupport.cs +++ /dev/null @@ -1,53 +0,0 @@ -#if UCS4 -using System; -using System.Runtime.InteropServices; -using System.Text; -using Mono.Unix; - -namespace Python.Runtime -{ - // The Utf32Marshaler was written Jonathan Pryor and has been placed - // in the PUBLIC DOMAIN. - public class Utf32Marshaler : ICustomMarshaler - { - private static Utf32Marshaler instance = new - Utf32Marshaler(); - - public static ICustomMarshaler GetInstance(string s) - { - return instance; - } - - public void CleanUpManagedData(object o) - { - } - - public void CleanUpNativeData(IntPtr pNativeData) - { - UnixMarshal.FreeHeap(pNativeData); - } - - public int GetNativeDataSize() - { - return IntPtr.Size; - } - - public IntPtr MarshalManagedToNative(object obj) - { - string s = obj as string; - if (s == null) - return IntPtr.Zero; - return UnixMarshal.StringToHeap(s, - Encoding.UTF32); - } - - public object MarshalNativeToManaged(IntPtr - pNativeData) - { - return UnixMarshal.PtrToString(pNativeData, - Encoding.UTF32); - } - } -} - -#endif diff --git a/src/runtime/nativecall.cs b/src/runtime/nativecall.cs index a37729ab2..b5bf25dd7 100644 --- a/src/runtime/nativecall.cs +++ b/src/runtime/nativecall.cs @@ -1,9 +1,8 @@ using System; -using System.Threading; -using System.Runtime.InteropServices; -using System.Collections; using System.Reflection; using System.Reflection.Emit; +using System.Runtime.InteropServices; +using System.Threading; namespace Python.Runtime { @@ -13,12 +12,10 @@ namespace Python.Runtime /// C API can just be wrapped with p/invoke, but there are some /// situations (specifically, calling functions through Python /// type structures) where we need to call functions indirectly. - /// /// This class uses Reflection.Emit to generate IJW thunks that /// support indirect calls to native code using various common /// call signatures. This is mainly a workaround for the fact /// that you can't spell an indirect call in C# (but can in IL). - /// /// Another approach that would work is for this to be turned /// into a separate utility program that could be run during the /// build process to generate the thunks as a separate assembly @@ -26,8 +23,32 @@ namespace Python.Runtime /// internal class NativeCall { - static AssemblyBuilder aBuilder; - static ModuleBuilder mBuilder; +#if NETSTANDARD + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void Void_1_Delegate(IntPtr a1); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate int Int_3_Delegate(IntPtr a1, IntPtr a2, IntPtr a3); + + public static void Void_Call_1(IntPtr fp, IntPtr a1) + { + ((Void_1_Delegate)Marshal.GetDelegateForFunctionPointer(fp, typeof(Void_1_Delegate)))(a1); + } + + public static IntPtr Call_3(IntPtr fp, IntPtr a1, IntPtr a2, IntPtr a3) + { + var d = (Interop.TernaryFunc)Marshal.GetDelegateForFunctionPointer(fp, typeof(Interop.TernaryFunc)); + return d(a1, a2, a3); + } + + + public static int Int_Call_3(IntPtr fp, IntPtr a1, IntPtr a2, IntPtr a3) + { + return ((Int_3_Delegate)Marshal.GetDelegateForFunctionPointer(fp, typeof(Int_3_Delegate)))(a1, a2, a3); + } +#else + private static AssemblyBuilder aBuilder; + private static ModuleBuilder mBuilder; public static INativeCall Impl; @@ -40,14 +61,13 @@ static NativeCall() // interface (defined below) and generate the required thunk // code based on the method signatures. - AssemblyName aname = new AssemblyName(); - aname.Name = "e__NativeCall_Assembly"; - AssemblyBuilderAccess aa = AssemblyBuilderAccess.Run; + var aname = new AssemblyName { Name = "e__NativeCall_Assembly" }; + var aa = AssemblyBuilderAccess.Run; aBuilder = Thread.GetDomain().DefineDynamicAssembly(aname, aa); mBuilder = aBuilder.DefineDynamicModule("e__NativeCall_Module"); - TypeAttributes ta = TypeAttributes.Public; + var ta = TypeAttributes.Public; TypeBuilder tBuilder = mBuilder.DefineType("e__NativeCall", ta); Type iType = typeof(INativeCall); @@ -72,8 +92,8 @@ private static void GenerateThunk(TypeBuilder tb, MethodInfo method) int count = pi.Length; int argc = count - 1; - Type[] args = new Type[count]; - for (int i = 0; i < count; i++) + var args = new Type[count]; + for (var i = 0; i < count; i++) { args[i] = pi[i].ParameterType; } @@ -84,16 +104,16 @@ private static void GenerateThunk(TypeBuilder tb, MethodInfo method) MethodAttributes.Virtual, method.ReturnType, args - ); + ); // Build the method signature for the actual native function. // This is essentially the signature of the wrapper method // minus the first argument (the passed in function pointer). - Type[] nargs = new Type[argc]; - for (int i = 1; i < count; i++) + var nargs = new Type[argc]; + for (var i = 1; i < count; i++) { - nargs[(i - 1)] = args[i]; + nargs[i - 1] = args[i]; } // IL generation: the (implicit) first argument of the method @@ -103,9 +123,9 @@ private static void GenerateThunk(TypeBuilder tb, MethodInfo method) ILGenerator il = mb.GetILGenerator(); - for (int i = 0; i < argc; i++) + for (var i = 0; i < argc; i++) { - il.Emit(OpCodes.Ldarg_S, (i + 2)); + il.Emit(OpCodes.Ldarg_S, i + 2); } il.Emit(OpCodes.Ldarg_1); @@ -114,12 +134,11 @@ private static void GenerateThunk(TypeBuilder tb, MethodInfo method) CallingConvention.Cdecl, method.ReturnType, nargs - ); + ); il.Emit(OpCodes.Ret); tb.DefineMethodOverride(mb, method); - return; } @@ -128,20 +147,19 @@ public static void Void_Call_1(IntPtr fp, IntPtr a1) Impl.Void_Call_1(fp, a1); } - public static IntPtr Call_3(IntPtr fp, IntPtr a1, IntPtr a2, - IntPtr a3) + public static IntPtr Call_3(IntPtr fp, IntPtr a1, IntPtr a2, IntPtr a3) { return Impl.Call_3(fp, a1, a2, a3); } - public static int Int_Call_3(IntPtr fp, IntPtr a1, IntPtr a2, - IntPtr a3) + public static int Int_Call_3(IntPtr fp, IntPtr a1, IntPtr a2, IntPtr a3) { return Impl.Int_Call_3(fp, a1, a2, a3); } +#endif } - +#if !NETSTANDARD /// /// Defines native call signatures to be generated by NativeCall. /// @@ -155,4 +173,5 @@ public interface INativeCall IntPtr Call_3(IntPtr funcPtr, IntPtr a1, IntPtr a2, IntPtr a3); } -} \ No newline at end of file +#endif +} diff --git a/src/runtime/overload.cs b/src/runtime/overload.cs index 2a339df66..6b48299e8 100644 --- a/src/runtime/overload.cs +++ b/src/runtime/overload.cs @@ -3,30 +3,28 @@ namespace Python.Runtime { - //======================================================================== - // Implements the __overloads__ attribute of method objects. This object - // supports the [] syntax to explicitly select an overload by signature. - //======================================================================== - + /// + /// Implements the __overloads__ attribute of method objects. This object + /// supports the [] syntax to explicitly select an overload by signature. + /// internal class OverloadMapper : ExtensionType { - MethodObject m; - IntPtr target; + private MethodObject m; + private IntPtr target; - public OverloadMapper(MethodObject m, IntPtr target) : base() + public OverloadMapper(MethodObject m, IntPtr target) { Runtime.XIncref(target); this.target = target; this.m = m; } - //==================================================================== - // Implement explicit overload selection using subscript syntax ([]). - //==================================================================== - + /// + /// Implement explicit overload selection using subscript syntax ([]). + /// public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) { - OverloadMapper self = (OverloadMapper)GetManagedObject(tp); + var self = (OverloadMapper)GetManagedObject(tp); // Note: if the type provides a non-generic method with N args // and a generic method that takes N params, then we always @@ -41,37 +39,34 @@ public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) MethodInfo mi = MethodBinder.MatchSignature(self.m.info, types); if (mi == null) { - string e = "No match found for signature"; + var e = "No match found for signature"; return Exceptions.RaiseTypeError(e); } - MethodBinding mb = new MethodBinding(self.m, self.target); - mb.info = mi; + var mb = new MethodBinding(self.m, self.target) { info = mi }; Runtime.XIncref(mb.pyHandle); return mb.pyHandle; } - //==================================================================== - // OverloadMapper __repr__ implementation. - //==================================================================== - + /// + /// OverloadMapper __repr__ implementation. + /// public static IntPtr tp_repr(IntPtr op) { - OverloadMapper self = (OverloadMapper)GetManagedObject(op); + var self = (OverloadMapper)GetManagedObject(op); IntPtr doc = self.m.GetDocString(); Runtime.XIncref(doc); return doc; } - //==================================================================== - // OverloadMapper dealloc implementation. - //==================================================================== - - public static new void tp_dealloc(IntPtr ob) + /// + /// OverloadMapper dealloc implementation. + /// + public new static void tp_dealloc(IntPtr ob) { - OverloadMapper self = (OverloadMapper)GetManagedObject(ob); + var self = (OverloadMapper)GetManagedObject(ob); Runtime.XDecref(self.target); - ExtensionType.FinalizeObject(self); + FinalizeObject(self); } } -} \ No newline at end of file +} diff --git a/src/runtime/polyfill/ReflectionPolifills.cs b/src/runtime/polyfill/ReflectionPolifills.cs new file mode 100644 index 000000000..a7e9c879a --- /dev/null +++ b/src/runtime/polyfill/ReflectionPolifills.cs @@ -0,0 +1,21 @@ +using System; +using System.Reflection; +using System.Reflection.Emit; + +namespace Python.Runtime +{ +#if NETSTANDARD + public static class ReflectionPolifills + { + public static AssemblyBuilder DefineDynamicAssembly(this AppDomain appDomain, AssemblyName assemblyName, AssemblyBuilderAccess assemblyBuilderAccess) + { + return AssemblyBuilder.DefineDynamicAssembly(assemblyName, assemblyBuilderAccess); + } + + public static Type CreateType(this TypeBuilder typeBuilder) + { + return typeBuilder.GetTypeInfo().GetType(); + } + } +#endif +} diff --git a/src/runtime/propertyobject.cs b/src/runtime/propertyobject.cs index 5bbf94d1a..f2c97f163 100644 --- a/src/runtime/propertyobject.cs +++ b/src/runtime/propertyobject.cs @@ -1,22 +1,20 @@ using System; -using System.Collections; using System.Reflection; using System.Security.Permissions; namespace Python.Runtime { - //======================================================================== - // Implements a Python descriptor type that manages CLR properties. - //======================================================================== - + /// + /// Implements a Python descriptor type that manages CLR properties. + /// internal class PropertyObject : ExtensionType { - PropertyInfo info; - MethodInfo getter; - MethodInfo setter; + private PropertyInfo info; + private MethodInfo getter; + private MethodInfo setter; - [StrongNameIdentityPermissionAttribute(SecurityAction.Assert)] - public PropertyObject(PropertyInfo md) : base() + [StrongNameIdentityPermission(SecurityAction.Assert)] + public PropertyObject(PropertyInfo md) { getter = md.GetGetMethod(true); setter = md.GetSetMethod(true); @@ -24,17 +22,16 @@ public PropertyObject(PropertyInfo md) : base() } - //==================================================================== - // Descriptor __get__ implementation. This method returns the - // value of the property on the given object. The returned value - // is converted to an appropriately typed Python object. - //==================================================================== - + /// + /// Descriptor __get__ implementation. This method returns the + /// value of the property on the given object. The returned value + /// is converted to an appropriately typed Python object. + /// public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { - PropertyObject self = (PropertyObject)GetManagedObject(ds); + var self = (PropertyObject)GetManagedObject(ds); MethodInfo getter = self.getter; - Object result; + object result; if (getter == null) @@ -42,14 +39,12 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) return Exceptions.RaiseTypeError("property cannot be read"); } - if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) + if (ob == IntPtr.Zero || ob == Runtime.PyNone) { - if (!(getter.IsStatic)) + if (!getter.IsStatic) { Exceptions.SetError(Exceptions.TypeError, - "instance property must be accessed through " + - "a class instance" - ); + "instance property must be accessed through a class instance"); return IntPtr.Zero; } @@ -64,7 +59,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) } } - CLRObject co = GetManagedObject(ob) as CLRObject; + var co = GetManagedObject(ob) as CLRObject; if (co == null) { return Exceptions.RaiseTypeError("invalid target"); @@ -87,17 +82,16 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) } - //==================================================================== - // Descriptor __set__ implementation. This method sets the value of - // a property based on the given Python value. The Python value must - // be convertible to the type of the property. - //==================================================================== - - public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) + /// + /// Descriptor __set__ implementation. This method sets the value of + /// a property based on the given Python value. The Python value must + /// be convertible to the type of the property. + /// + public new static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { - PropertyObject self = (PropertyObject)GetManagedObject(ds); + var self = (PropertyObject)GetManagedObject(ds); MethodInfo setter = self.setter; - Object newval; + object newval; if (val == IntPtr.Zero) { @@ -112,21 +106,18 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) } - if (!Converter.ToManaged(val, self.info.PropertyType, out newval, - true)) + if (!Converter.ToManaged(val, self.info.PropertyType, out newval, true)) { return -1; } bool is_static = setter.IsStatic; - if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) + if (ob == IntPtr.Zero || ob == Runtime.PyNone) { - if (!(is_static)) + if (!is_static) { - Exceptions.RaiseTypeError( - "instance property must be set on an instance" - ); + Exceptions.RaiseTypeError("instance property must be set on an instance"); return -1; } } @@ -135,7 +126,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { if (!is_static) { - CLRObject co = GetManagedObject(ob) as CLRObject; + var co = GetManagedObject(ob) as CLRObject; if (co == null) { Exceptions.RaiseTypeError("invalid target"); @@ -161,15 +152,13 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) } - //==================================================================== - // Descriptor __repr__ implementation. - //==================================================================== - + /// + /// Descriptor __repr__ implementation. + /// public static IntPtr tp_repr(IntPtr ob) { - PropertyObject self = (PropertyObject)GetManagedObject(ob); - string s = String.Format("", self.info.Name); - return Runtime.PyString_FromStringAndSize(s, s.Length); + var self = (PropertyObject)GetManagedObject(ob); + return Runtime.PyString_FromString($""); } } -} \ No newline at end of file +} diff --git a/src/runtime/pyansistring.cs b/src/runtime/pyansistring.cs index 1a2cb7955..3d1d6ab68 100644 --- a/src/runtime/pyansistring.cs +++ b/src/runtime/pyansistring.cs @@ -7,7 +7,6 @@ public class PyAnsiString : PySequence /// /// PyAnsiString Constructor /// - /// /// /// Creates a new PyAnsiString from an existing object reference. Note /// that the instance assumes ownership of the object reference. @@ -21,14 +20,12 @@ public PyAnsiString(IntPtr ptr) : base(ptr) /// /// PyString Constructor /// - /// /// /// Copy constructor - obtain a PyAnsiString from a generic PyObject. /// An ArgumentException will be thrown if the given object is not /// a Python string object. /// public PyAnsiString(PyObject o) - : base() { if (!IsStringType(o)) { @@ -42,25 +39,19 @@ public PyAnsiString(PyObject o) /// /// PyAnsiString Constructor /// - /// /// /// Creates a Python string from a managed string. /// public PyAnsiString(string s) - : base() { - obj = Runtime.PyString_FromStringAndSize(s, s.Length); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + obj = Runtime.PyString_FromString(s); + Runtime.CheckExceptionOccurred(); } /// /// IsStringType Method /// - /// /// /// Returns true if the given object is a Python string. /// @@ -69,4 +60,4 @@ public static bool IsStringType(PyObject value) return Runtime.PyString_Check(value.obj); } } -} \ No newline at end of file +} diff --git a/src/runtime/pydict.cs b/src/runtime/pydict.cs index fc8b98377..7237d1990 100644 --- a/src/runtime/pydict.cs +++ b/src/runtime/pydict.cs @@ -1,18 +1,18 @@ using System; -using System.Runtime.InteropServices; namespace Python.Runtime { /// /// Represents a Python dictionary object. See the documentation at - /// http://www.python.org/doc/current/api/dictObjects.html for details. + /// PY2: https://docs.python.org/2/c-api/dict.html + /// PY3: https://docs.python.org/3/c-api/dict.html + /// for details. /// public class PyDict : PyObject { /// /// PyDict Constructor /// - /// /// /// Creates a new PyDict from an existing object reference. Note /// that the instance assumes ownership of the object reference. @@ -26,11 +26,10 @@ public PyDict(IntPtr ptr) : base(ptr) /// /// PyDict Constructor /// - /// /// /// Creates a new Python dictionary object. /// - public PyDict() : base() + public PyDict() { obj = Runtime.PyDict_New(); if (obj == IntPtr.Zero) @@ -43,13 +42,12 @@ public PyDict() : base() /// /// PyDict Constructor /// - /// /// /// Copy constructor - obtain a PyDict from a generic PyObject. An /// ArgumentException will be thrown if the given object is not a /// Python dictionary object. /// - public PyDict(PyObject o) : base() + public PyDict(PyObject o) { if (!IsDictType(o)) { @@ -63,7 +61,6 @@ public PyDict(PyObject o) : base() /// /// IsDictType Method /// - /// /// /// Returns true if the given object is a Python dictionary. /// @@ -76,34 +73,33 @@ public static bool IsDictType(PyObject value) /// /// HasKey Method /// - /// /// /// Returns true if the object key appears in the dictionary. /// public bool HasKey(PyObject key) { - return (Runtime.PyMapping_HasKey(obj, key.obj) != 0); + return Runtime.PyMapping_HasKey(obj, key.obj) != 0; } /// /// HasKey Method /// - /// /// /// Returns true if the string key appears in the dictionary. /// public bool HasKey(string key) { - using (PyString str = new PyString(key)) + using (var str = new PyString(key)) + { return HasKey(str); + } } /// /// Keys Method /// - /// /// /// Returns a sequence containing the keys of the dictionary. /// @@ -121,7 +117,6 @@ public PyObject Keys() /// /// Values Method /// - /// /// /// Returns a sequence containing the values of the dictionary. /// @@ -139,7 +134,6 @@ public PyObject Values() /// /// Items Method /// - /// /// /// Returns a sequence containing the items of the dictionary. /// @@ -157,7 +151,6 @@ public PyObject Items() /// /// Copy Method /// - /// /// /// Returns a copy of the dictionary. /// @@ -175,7 +168,6 @@ public PyDict Copy() /// /// Update Method /// - /// /// /// Update the dictionary from another dictionary. /// @@ -192,7 +184,6 @@ public void Update(PyObject other) /// /// Clear Method /// - /// /// /// Clears the dictionary. /// @@ -201,4 +192,4 @@ public void Clear() Runtime.PyDict_Clear(obj); } } -} \ No newline at end of file +} diff --git a/src/runtime/pyfloat.cs b/src/runtime/pyfloat.cs index 27a13f184..edfaca542 100644 --- a/src/runtime/pyfloat.cs +++ b/src/runtime/pyfloat.cs @@ -1,18 +1,18 @@ using System; -using System.Runtime.InteropServices; namespace Python.Runtime { /// /// Represents a Python float object. See the documentation at - /// http://www.python.org/doc/current/api/floatObjects.html + /// PY2: https://docs.python.org/2/c-api/float.html + /// PY3: https://docs.python.org/3/c-api/float.html + /// for details. /// public class PyFloat : PyNumber { /// /// PyFloat Constructor /// - /// /// /// Creates a new PyFloat from an existing object reference. Note /// that the instance assumes ownership of the object reference. @@ -26,13 +26,12 @@ public PyFloat(IntPtr ptr) : base(ptr) /// /// PyFloat Constructor /// - /// /// /// Copy constructor - obtain a PyFloat from a generic PyObject. An /// ArgumentException will be thrown if the given object is not a /// Python float object. /// - public PyFloat(PyObject o) : base() + public PyFloat(PyObject o) { if (!IsFloatType(o)) { @@ -46,36 +45,28 @@ public PyFloat(PyObject o) : base() /// /// PyFloat Constructor /// - /// /// /// Creates a new Python float from a double value. /// - public PyFloat(double value) : base() + public PyFloat(double value) { obj = Runtime.PyFloat_FromDouble(value); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); } /// /// PyFloat Constructor /// - /// /// /// Creates a new Python float from a string value. /// - public PyFloat(string value) : base() + public PyFloat(string value) { - using (PyString s = new PyString(value)) + using (var s = new PyString(value)) { obj = Runtime.PyFloat_FromString(s.obj, IntPtr.Zero); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); } } @@ -83,7 +74,6 @@ public PyFloat(string value) : base() /// /// IsFloatType Method /// - /// /// /// Returns true if the given object is a Python float. /// @@ -96,8 +86,6 @@ public static bool IsFloatType(PyObject value) /// /// AsFloat Method /// - /// - /// /// /// Convert a Python object to a Python float if possible, raising /// a PythonException if the conversion is not possible. This is @@ -106,11 +94,8 @@ public static bool IsFloatType(PyObject value) public static PyFloat AsFloat(PyObject value) { IntPtr op = Runtime.PyNumber_Float(value.obj); - if (op == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); return new PyFloat(op); } } -} \ No newline at end of file +} diff --git a/src/runtime/pyint.cs b/src/runtime/pyint.cs index 935f54a8b..f6911d9d7 100644 --- a/src/runtime/pyint.cs +++ b/src/runtime/pyint.cs @@ -1,18 +1,18 @@ using System; -using System.Runtime.InteropServices; namespace Python.Runtime { /// /// Represents a Python integer object. See the documentation at - /// http://www.python.org/doc/current/api/intObjects.html for details. + /// PY2: https://docs.python.org/2/c-api/int.html + /// PY3: No equivalent + /// for details. /// public class PyInt : PyNumber { /// /// PyInt Constructor /// - /// /// /// Creates a new PyInt from an existing object reference. Note /// that the instance assumes ownership of the object reference. @@ -26,13 +26,12 @@ public PyInt(IntPtr ptr) : base(ptr) /// /// PyInt Constructor /// - /// /// /// Copy constructor - obtain a PyInt from a generic PyObject. An /// ArgumentException will be thrown if the given object is not a /// Python int object. /// - public PyInt(PyObject o) : base() + public PyInt(PyObject o) { if (!IsIntType(o)) { @@ -46,59 +45,46 @@ public PyInt(PyObject o) : base() /// /// PyInt Constructor /// - /// /// /// Creates a new Python int from an int32 value. /// - public PyInt(int value) : base() + public PyInt(int value) { obj = Runtime.PyInt_FromInt32(value); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); } /// /// PyInt Constructor /// - /// /// /// Creates a new Python int from a uint32 value. /// [CLSCompliant(false)] public PyInt(uint value) : base(IntPtr.Zero) { - obj = Runtime.PyInt_FromInt64((long)value); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + obj = Runtime.PyInt_FromInt64(value); + Runtime.CheckExceptionOccurred(); } /// /// PyInt Constructor /// - /// /// /// Creates a new Python int from an int64 value. /// public PyInt(long value) : base(IntPtr.Zero) { obj = Runtime.PyInt_FromInt64(value); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); } /// /// PyInt Constructor /// - /// /// /// Creates a new Python int from a uint64 value. /// @@ -106,17 +92,13 @@ public PyInt(long value) : base(IntPtr.Zero) public PyInt(ulong value) : base(IntPtr.Zero) { obj = Runtime.PyInt_FromInt64((long)value); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); } /// /// PyInt Constructor /// - /// /// /// Creates a new Python int from an int16 value. /// @@ -128,7 +110,6 @@ public PyInt(short value) : this((int)value) /// /// PyInt Constructor /// - /// /// /// Creates a new Python int from a uint16 value. /// @@ -141,7 +122,6 @@ public PyInt(ushort value) : this((int)value) /// /// PyInt Constructor /// - /// /// /// Creates a new Python int from a byte value. /// @@ -153,7 +133,6 @@ public PyInt(byte value) : this((int)value) /// /// PyInt Constructor /// - /// /// /// Creates a new Python int from an sbyte value. /// @@ -166,24 +145,19 @@ public PyInt(sbyte value) : this((int)value) /// /// PyInt Constructor /// - /// /// /// Creates a new Python int from a string value. /// - public PyInt(string value) : base() + public PyInt(string value) { obj = Runtime.PyInt_FromString(value, IntPtr.Zero, 0); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); } /// /// IsIntType Method /// - /// /// /// Returns true if the given object is a Python int. /// @@ -196,8 +170,6 @@ public static bool IsIntType(PyObject value) /// /// AsInt Method /// - /// - /// /// /// Convert a Python object to a Python int if possible, raising /// a PythonException if the conversion is not possible. This is @@ -206,10 +178,7 @@ public static bool IsIntType(PyObject value) public static PyInt AsInt(PyObject value) { IntPtr op = Runtime.PyNumber_Int(value.obj); - if (op == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); return new PyInt(op); } @@ -217,20 +186,18 @@ public static PyInt AsInt(PyObject value) /// /// ToInt16 Method /// - /// /// /// Return the value of the Python int object as an int16. /// public short ToInt16() { - return System.Convert.ToInt16(this.ToInt32()); + return Convert.ToInt16(ToInt32()); } /// /// ToInt32 Method /// - /// /// /// Return the value of the Python int object as an int32. /// @@ -243,13 +210,12 @@ public int ToInt32() /// /// ToInt64 Method /// - /// /// /// Return the value of the Python int object as an int64. /// public long ToInt64() { - return System.Convert.ToInt64(this.ToInt32()); + return Convert.ToInt64(ToInt32()); } } -} \ No newline at end of file +} diff --git a/src/runtime/pyiter.cs b/src/runtime/pyiter.cs index 5d11fb4d4..ee07bcecf 100644 --- a/src/runtime/pyiter.cs +++ b/src/runtime/pyiter.cs @@ -5,16 +5,17 @@ namespace Python.Runtime { /// /// Represents a standard Python iterator object. See the documentation at - /// http://www.python.org/doc/2.4.4/api/iterator.html for details. + /// PY2: https://docs.python.org/2/c-api/iterator.html + /// PY3: https://docs.python.org/3/c-api/iterator.html + /// for details. /// public class PyIter : PyObject, IEnumerator { - private PyObject _current = null; + private PyObject _current; /// /// PyIter Constructor /// - /// /// /// Creates a new PyIter from an existing iterator reference. Note /// that the instance assumes ownership of the object reference. @@ -27,15 +28,16 @@ public PyIter(IntPtr ptr) : base(ptr) /// /// PyIter Constructor /// - /// /// /// Creates a Python iterator from an iterable. Like doing "iter(iterable)" in python. /// - public PyIter(PyObject iterable) : base() + public PyIter(PyObject iterable) { obj = Runtime.PyObject_GetIter(iterable.obj); if (obj == IntPtr.Zero) + { throw new PythonException(); + } } protected override void Dispose(bool disposing) @@ -48,8 +50,6 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - #region IEnumerator Members - public bool MoveNext() { // dispose of the previous object, if there was one @@ -61,7 +61,9 @@ public bool MoveNext() IntPtr next = Runtime.PyIter_Next(obj); if (next == IntPtr.Zero) + { return false; + } _current = new PyObject(next); return true; @@ -76,7 +78,5 @@ public object Current { get { return _current; } } - - #endregion } -} \ No newline at end of file +} diff --git a/src/runtime/pylist.cs b/src/runtime/pylist.cs index bdbc806fd..b22d9d51f 100644 --- a/src/runtime/pylist.cs +++ b/src/runtime/pylist.cs @@ -4,14 +4,15 @@ namespace Python.Runtime { /// /// Represents a standard Python list object. See the documentation at - /// http://www.python.org/doc/current/api/listObjects.html for details. + /// PY2: https://docs.python.org/2/c-api/list.html + /// PY3: https://docs.python.org/3/c-api/list.html + /// for details. /// public class PyList : PySequence { /// /// PyList Constructor /// - /// /// /// Creates a new PyList from an existing object reference. Note /// that the instance assumes ownership of the object reference. @@ -25,13 +26,12 @@ public PyList(IntPtr ptr) : base(ptr) /// /// PyList Constructor /// - /// /// /// Copy constructor - obtain a PyList from a generic PyObject. An /// ArgumentException will be thrown if the given object is not a /// Python list object. /// - public PyList(PyObject o) : base() + public PyList(PyObject o) { if (!IsListType(o)) { @@ -45,11 +45,10 @@ public PyList(PyObject o) : base() /// /// PyList Constructor /// - /// /// /// Creates a new empty Python list object. /// - public PyList() : base() + public PyList() { obj = Runtime.PyList_New(0); if (obj == IntPtr.Zero) @@ -62,15 +61,14 @@ public PyList() : base() /// /// PyList Constructor /// - /// /// /// Creates a new Python list object from an array of PyObjects. /// - public PyList(PyObject[] items) : base() + public PyList(PyObject[] items) { int count = items.Length; obj = Runtime.PyList_New(count); - for (int i = 0; i < count; i++) + for (var i = 0; i < count; i++) { IntPtr ptr = items[i].obj; Runtime.XIncref(ptr); @@ -86,7 +84,6 @@ public PyList(PyObject[] items) : base() /// /// IsListType Method /// - /// /// /// Returns true if the given object is a Python list. /// @@ -99,7 +96,6 @@ public static bool IsListType(PyObject value) /// /// AsList Method /// - /// /// /// Converts a Python object to a Python list if possible, raising /// a PythonException if the conversion is not possible. This is @@ -119,7 +115,6 @@ public static PyList AsList(PyObject value) /// /// Append Method /// - /// /// /// Append an item to the list object. /// @@ -135,7 +130,6 @@ public void Append(PyObject item) /// /// Insert Method /// - /// /// /// Insert an item in the list object at the given index. /// @@ -152,7 +146,6 @@ public void Insert(int index, PyObject item) /// /// Reverse Method /// - /// /// /// Reverse the order of the list object in place. /// @@ -169,7 +162,6 @@ public void Reverse() /// /// Sort Method /// - /// /// /// Sort the list in place. /// @@ -182,4 +174,4 @@ public void Sort() } } } -} \ No newline at end of file +} diff --git a/src/runtime/pylong.cs b/src/runtime/pylong.cs index 63c613402..286af40df 100644 --- a/src/runtime/pylong.cs +++ b/src/runtime/pylong.cs @@ -4,14 +4,15 @@ namespace Python.Runtime { /// /// Represents a Python long int object. See the documentation at - /// http://www.python.org/doc/current/api/longObjects.html + /// PY2: https://docs.python.org/2/c-api/long.html + /// PY3: https://docs.python.org/3/c-api/long.html + /// for details. /// public class PyLong : PyNumber { /// /// PyLong Constructor /// - /// /// /// Creates a new PyLong from an existing object reference. Note /// that the instance assumes ownership of the object reference. @@ -25,13 +26,12 @@ public PyLong(IntPtr ptr) : base(ptr) /// /// PyLong Constructor /// - /// /// /// Copy constructor - obtain a PyLong from a generic PyObject. An /// ArgumentException will be thrown if the given object is not a /// Python long object. /// - public PyLong(PyObject o) : base() + public PyLong(PyObject o) { if (!IsLongType(o)) { @@ -45,181 +45,140 @@ public PyLong(PyObject o) : base() /// /// PyLong Constructor /// - /// /// /// Creates a new PyLong from an int32 value. /// - public PyLong(int value) : base() + public PyLong(int value) { - obj = Runtime.PyLong_FromLong((long)value); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + obj = Runtime.PyLong_FromLong(value); + Runtime.CheckExceptionOccurred(); } /// /// PyLong Constructor /// - /// /// /// Creates a new PyLong from a uint32 value. /// [CLSCompliant(false)] - public PyLong(uint value) : base() + public PyLong(uint value) { - obj = Runtime.PyLong_FromLong((long)value); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + obj = Runtime.PyLong_FromLong(value); + Runtime.CheckExceptionOccurred(); } /// /// PyLong Constructor /// - /// /// /// Creates a new PyLong from an int64 value. /// - public PyLong(long value) : base() + public PyLong(long value) { obj = Runtime.PyLong_FromLongLong(value); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); } /// /// PyLong Constructor /// - /// /// /// Creates a new PyLong from a uint64 value. /// [CLSCompliant(false)] - public PyLong(ulong value) : base() + public PyLong(ulong value) { obj = Runtime.PyLong_FromUnsignedLongLong(value); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); } /// /// PyLong Constructor /// - /// /// /// Creates a new PyLong from an int16 value. /// - public PyLong(short value) : base() + public PyLong(short value) { - obj = Runtime.PyLong_FromLong((long)value); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + obj = Runtime.PyLong_FromLong(value); + Runtime.CheckExceptionOccurred(); } /// /// PyLong Constructor /// - /// /// /// Creates a new PyLong from an uint16 value. /// [CLSCompliant(false)] - public PyLong(ushort value) : base() + public PyLong(ushort value) { - obj = Runtime.PyLong_FromLong((long)value); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + obj = Runtime.PyLong_FromLong(value); + Runtime.CheckExceptionOccurred(); } /// /// PyLong Constructor /// - /// /// /// Creates a new PyLong from a byte value. /// - public PyLong(byte value) : base() + public PyLong(byte value) { - obj = Runtime.PyLong_FromLong((long)value); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + obj = Runtime.PyLong_FromLong(value); + Runtime.CheckExceptionOccurred(); } /// /// PyLong Constructor /// - /// /// /// Creates a new PyLong from an sbyte value. /// [CLSCompliant(false)] - public PyLong(sbyte value) : base() + public PyLong(sbyte value) { - obj = Runtime.PyLong_FromLong((long)value); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + obj = Runtime.PyLong_FromLong(value); + Runtime.CheckExceptionOccurred(); } /// /// PyLong Constructor /// - /// /// /// Creates a new PyLong from an double value. /// - public PyLong(double value) : base() + public PyLong(double value) { obj = Runtime.PyLong_FromDouble(value); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); } /// /// PyLong Constructor /// - /// /// /// Creates a new PyLong from a string value. /// - public PyLong(string value) : base() + public PyLong(string value) { obj = Runtime.PyLong_FromString(value, IntPtr.Zero, 0); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); } /// /// IsLongType Method /// - /// /// /// Returns true if the given object is a Python long. /// @@ -232,8 +191,6 @@ public static bool IsLongType(PyObject value) /// /// AsLong Method /// - /// - /// /// /// Convert a Python object to a Python long if possible, raising /// a PythonException if the conversion is not possible. This is @@ -242,43 +199,37 @@ public static bool IsLongType(PyObject value) public static PyLong AsLong(PyObject value) { IntPtr op = Runtime.PyNumber_Long(value.obj); - if (op == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); return new PyLong(op); } /// /// ToInt16 Method /// - /// /// /// Return the value of the Python long object as an int16. /// public short ToInt16() { - return System.Convert.ToInt16(this.ToInt64()); + return Convert.ToInt16(ToInt64()); } /// /// ToInt32 Method /// - /// /// /// Return the value of the Python long object as an int32. /// public int ToInt32() { - return System.Convert.ToInt32(this.ToInt64()); + return Convert.ToInt32(ToInt64()); } /// /// ToInt64 Method /// - /// /// /// Return the value of the Python long object as an int64. /// @@ -287,4 +238,4 @@ public long ToInt64() return Runtime.PyLong_AsLongLong(obj); } } -} \ No newline at end of file +} diff --git a/src/runtime/pynumber.cs b/src/runtime/pynumber.cs index c8da3e7a6..4f7373a8c 100644 --- a/src/runtime/pynumber.cs +++ b/src/runtime/pynumber.cs @@ -5,15 +5,20 @@ namespace Python.Runtime /// /// Represents a generic Python number. The methods of this class are /// equivalent to the Python "abstract number API". See - /// http://www.python.org/doc/current/api/number.html for details. + /// PY2: https://docs.python.org/2/c-api/number.html + /// PY3: https://docs.python.org/3/c-api/number.html + /// for details. /// + /// + /// TODO: add all of the PyNumber_XXX methods. + /// public class PyNumber : PyObject { protected PyNumber(IntPtr ptr) : base(ptr) { } - protected PyNumber() : base() + protected PyNumber() { } @@ -21,7 +26,6 @@ protected PyNumber() : base() /// /// IsNumberType Method /// - /// /// /// Returns true if the given object is a Python numeric type. /// @@ -29,8 +33,5 @@ public static bool IsNumberType(PyObject value) { return Runtime.PyNumber_Check(value.obj); } - - - // TODO: add all of the PyNumber_XXX methods. } -} \ No newline at end of file +} diff --git a/src/runtime/pyobject.cs b/src/runtime/pyobject.cs index 781f6313d..0d186bf4e 100644 --- a/src/runtime/pyobject.cs +++ b/src/runtime/pyobject.cs @@ -1,16 +1,18 @@ using System; +using System.Collections; using System.Dynamic; using System.Linq.Expressions; -using System.Collections; namespace Python.Runtime { /// /// Represents a generic Python object. The methods of this class are /// generally equivalent to the Python "abstract object API". See - /// http://www.python.org/doc/current/api/object.html for details. + /// PY2: https://docs.python.org/2/c-api/object.html + /// PY3: https://docs.python.org/3/c-api/object.html + /// for details. /// - public class PyObject : DynamicObject, IDisposable + public class PyObject : DynamicObject, IEnumerable, IDisposable { protected internal IntPtr obj = IntPtr.Zero; private bool disposed = false; @@ -18,7 +20,6 @@ public class PyObject : DynamicObject, IDisposable /// /// PyObject Constructor /// - /// /// /// Creates a new PyObject from an IntPtr object reference. Note that /// the PyObject instance assumes ownership of the object reference @@ -42,6 +43,10 @@ protected PyObject() ~PyObject() { + // We needs to disable Finalizers until it's valid implementation. + // Current implementation can produce low probability floating bugs. + return; + Dispose(); } @@ -49,7 +54,6 @@ protected PyObject() /// /// Handle Property /// - /// /// /// Gets the native handle of the underlying Python object. This /// value is generally for internal use by the PythonNet runtime. @@ -63,7 +67,6 @@ public IntPtr Handle /// /// FromManagedObject Method /// - /// /// /// Given an arbitrary managed object, return a Python instance that /// reflects the managed object. @@ -84,26 +87,45 @@ public static PyObject FromManagedObject(object ob) /// /// AsManagedObject Method /// - /// /// /// Return a managed object of the given type, based on the /// value of the Python object. /// public object AsManagedObject(Type t) { - Object result; - if (!Converter.ToManaged(this.obj, t, out result, false)) + object result; + if (!Converter.ToManaged(obj, t, out result, false)) { throw new InvalidCastException("cannot convert object to target type"); } return result; } + + /// + /// As Method + /// + /// + /// Return a managed object of the given type, based on the + /// value of the Python object. + /// + public T As() + { + if (typeof(T) == typeof(PyObject) || typeof(T) == typeof(object)) + { + return (T)(this as object); + } + object result; + if (!Converter.ToManaged(obj, typeof(T), out result, false)) + { + throw new InvalidCastException("cannot convert object to target type"); + } + return (T)result; + } /// /// Dispose Method /// - /// /// /// The Dispose method provides a way to explicitly release the /// Python object represented by a PyObject instance. It is a good @@ -116,7 +138,7 @@ protected virtual void Dispose(bool disposing) { if (!disposed) { - if (Runtime.Py_IsInitialized() > 0) + if (Runtime.Py_IsInitialized() > 0 && !Runtime.IsFinalizing) { IntPtr gs = PythonEngine.AcquireLock(); Runtime.XDecref(obj); @@ -126,7 +148,7 @@ protected virtual void Dispose(bool disposing) disposed = true; } } - + public void Dispose() { Dispose(true); @@ -137,7 +159,6 @@ public void Dispose() /// /// GetPythonType Method /// - /// /// /// Returns the Python type of the object. This method is equivalent /// to the Python expression: type(object). @@ -152,7 +173,6 @@ public PyObject GetPythonType() /// /// TypeCheck Method /// - /// /// /// Returns true if the object o is of type typeOrClass or a subtype /// of typeOrClass. @@ -166,34 +186,31 @@ public bool TypeCheck(PyObject typeOrClass) /// /// HasAttr Method /// - /// /// /// Returns true if the object has an attribute with the given name. /// public bool HasAttr(string name) { - return (Runtime.PyObject_HasAttrString(obj, name) != 0); + return Runtime.PyObject_HasAttrString(obj, name) != 0; } /// /// HasAttr Method /// - /// /// /// Returns true if the object has an attribute with the given name, /// where name is a PyObject wrapping a string or unicode object. /// public bool HasAttr(PyObject name) { - return (Runtime.PyObject_HasAttr(obj, name.obj) != 0); + return Runtime.PyObject_HasAttr(obj, name.obj) != 0; } /// /// GetAttr Method /// - /// /// /// Returns the named attribute of the Python object, or raises a /// PythonException if the attribute access fails. @@ -212,7 +229,6 @@ public PyObject GetAttr(string name) /// /// GetAttr Method /// - /// /// /// Returns the named attribute of the Python object, or the given /// default object if the attribute access fails. @@ -232,7 +248,6 @@ public PyObject GetAttr(string name, PyObject _default) /// /// GetAttr Method /// - /// /// /// Returns the named attribute of the Python object or raises a /// PythonException if the attribute access fails. The name argument @@ -252,7 +267,6 @@ public PyObject GetAttr(PyObject name) /// /// GetAttr Method /// - /// /// /// Returns the named attribute of the Python object, or the given /// default object if the attribute access fails. The name argument @@ -273,7 +287,6 @@ public PyObject GetAttr(PyObject name, PyObject _default) /// /// SetAttr Method /// - /// /// /// Set an attribute of the object with the given name and value. This /// method throws a PythonException if the attribute set fails. @@ -291,7 +304,6 @@ public void SetAttr(string name, PyObject value) /// /// SetAttr Method /// - /// /// /// Set an attribute of the object with the given name and value, /// where the name is a Python string or unicode object. This method @@ -310,7 +322,6 @@ public void SetAttr(PyObject name, PyObject value) /// /// DelAttr Method /// - /// /// /// Delete the named attribute of the Python object. This method /// throws a PythonException if the attribute set fails. @@ -328,7 +339,6 @@ public void DelAttr(string name) /// /// DelAttr Method /// - /// /// /// Delete the named attribute of the Python object, where name is a /// PyObject wrapping a Python string or unicode object. This method @@ -347,7 +357,6 @@ public void DelAttr(PyObject name) /// /// GetItem Method /// - /// /// /// For objects that support the Python sequence or mapping protocols, /// return the item at the given object index. This method raises a @@ -367,7 +376,6 @@ public virtual PyObject GetItem(PyObject key) /// /// GetItem Method /// - /// /// /// For objects that support the Python sequence or mapping protocols, /// return the item at the given string index. This method raises a @@ -375,7 +383,7 @@ public virtual PyObject GetItem(PyObject key) /// public virtual PyObject GetItem(string key) { - using (PyString pyKey = new PyString(key)) + using (var pyKey = new PyString(key)) { return GetItem(pyKey); } @@ -385,7 +393,6 @@ public virtual PyObject GetItem(string key) /// /// GetItem Method /// - /// /// /// For objects that support the Python sequence or mapping protocols, /// return the item at the given numeric index. This method raises a @@ -393,9 +400,9 @@ public virtual PyObject GetItem(string key) /// public virtual PyObject GetItem(int index) { - using (PyInt key = new PyInt(index)) + using (var key = new PyInt(index)) { - return GetItem((PyObject)key); + return GetItem(key); } } @@ -403,7 +410,6 @@ public virtual PyObject GetItem(int index) /// /// SetItem Method /// - /// /// /// For objects that support the Python sequence or mapping protocols, /// set the item at the given object index to the given value. This @@ -422,7 +428,6 @@ public virtual void SetItem(PyObject key, PyObject value) /// /// SetItem Method /// - /// /// /// For objects that support the Python sequence or mapping protocols, /// set the item at the given string index to the given value. This @@ -430,7 +435,7 @@ public virtual void SetItem(PyObject key, PyObject value) /// public virtual void SetItem(string key, PyObject value) { - using (PyString pyKey = new PyString(key)) + using (var pyKey = new PyString(key)) { SetItem(pyKey, value); } @@ -440,7 +445,6 @@ public virtual void SetItem(string key, PyObject value) /// /// SetItem Method /// - /// /// /// For objects that support the Python sequence or mapping protocols, /// set the item at the given numeric index to the given value. This @@ -448,7 +452,7 @@ public virtual void SetItem(string key, PyObject value) /// public virtual void SetItem(int index, PyObject value) { - using (PyInt pyindex = new PyInt(index)) + using (var pyindex = new PyInt(index)) { SetItem(pyindex, value); } @@ -458,7 +462,6 @@ public virtual void SetItem(int index, PyObject value) /// /// DelItem Method /// - /// /// /// For objects that support the Python sequence or mapping protocols, /// delete the item at the given object index. This method raises a @@ -477,7 +480,6 @@ public virtual void DelItem(PyObject key) /// /// DelItem Method /// - /// /// /// For objects that support the Python sequence or mapping protocols, /// delete the item at the given string index. This method raises a @@ -485,7 +487,7 @@ public virtual void DelItem(PyObject key) /// public virtual void DelItem(string key) { - using (PyString pyKey = new PyString(key)) + using (var pyKey = new PyString(key)) { DelItem(pyKey); } @@ -495,7 +497,6 @@ public virtual void DelItem(string key) /// /// DelItem Method /// - /// /// /// For objects that support the Python sequence or mapping protocols, /// delete the item at the given numeric index. This method raises a @@ -503,7 +504,7 @@ public virtual void DelItem(string key) /// public virtual void DelItem(int index) { - using (PyInt pyindex = new PyInt(index)) + using (var pyindex = new PyInt(index)) { DelItem(pyindex); } @@ -513,7 +514,6 @@ public virtual void DelItem(int index) /// /// Length Method /// - /// /// /// Returns the length for objects that support the Python sequence /// protocol, or 0 if the object does not support the protocol. @@ -533,7 +533,6 @@ public virtual int Length() /// /// String Indexer /// - /// /// /// Provides a shorthand for the string versions of the GetItem and /// SetItem methods. @@ -548,7 +547,6 @@ public virtual PyObject this[string key] /// /// PyObject Indexer /// - /// /// /// Provides a shorthand for the object versions of the GetItem and /// SetItem methods. @@ -563,7 +561,6 @@ public virtual PyObject this[PyObject key] /// /// Numeric Indexer /// - /// /// /// Provides a shorthand for the numeric versions of the GetItem and /// SetItem methods. @@ -578,7 +575,6 @@ public virtual PyObject this[int index] /// /// GetIterator Method /// - /// /// /// Return a new (Python) iterator for the object. This is equivalent /// to the Python expression "iter(object)". A PythonException will be @@ -597,7 +593,6 @@ public PyObject GetIterator() /// /// GetEnumerator Method /// - /// /// /// Return a new PyIter object for the object. This allows any iterable /// python object to be iterated over in C#. A PythonException will be @@ -612,14 +607,13 @@ public IEnumerator GetEnumerator() /// /// Invoke Method /// - /// /// /// Invoke the callable object with the given arguments, passed as a /// PyObject[]. A PythonException is raised if the invokation fails. /// public PyObject Invoke(params PyObject[] args) { - PyTuple t = new PyTuple(args); + var t = new PyTuple(args); IntPtr r = Runtime.PyObject_Call(obj, t.obj, IntPtr.Zero); t.Dispose(); if (r == IntPtr.Zero) @@ -633,7 +627,6 @@ public PyObject Invoke(params PyObject[] args) /// /// Invoke Method /// - /// /// /// Invoke the callable object with the given arguments, passed as a /// Python tuple. A PythonException is raised if the invokation fails. @@ -652,14 +645,13 @@ public PyObject Invoke(PyTuple args) /// /// Invoke Method /// - /// /// /// Invoke the callable object with the given positional and keyword /// arguments. A PythonException is raised if the invokation fails. /// public PyObject Invoke(PyObject[] args, PyDict kw) { - PyTuple t = new PyTuple(args); + var t = new PyTuple(args); IntPtr r = Runtime.PyObject_Call(obj, t.obj, kw != null ? kw.obj : IntPtr.Zero); t.Dispose(); if (r == IntPtr.Zero) @@ -673,7 +665,6 @@ public PyObject Invoke(PyObject[] args, PyDict kw) /// /// Invoke Method /// - /// /// /// Invoke the callable object with the given positional and keyword /// arguments. A PythonException is raised if the invokation fails. @@ -692,7 +683,6 @@ public PyObject Invoke(PyTuple args, PyDict kw) /// /// InvokeMethod Method /// - /// /// /// Invoke the named method of the object with the given arguments. /// A PythonException is raised if the invokation is unsuccessful. @@ -709,7 +699,6 @@ public PyObject InvokeMethod(string name, params PyObject[] args) /// /// InvokeMethod Method /// - /// /// /// Invoke the named method of the object with the given arguments. /// A PythonException is raised if the invokation is unsuccessful. @@ -726,7 +715,6 @@ public PyObject InvokeMethod(string name, PyTuple args) /// /// InvokeMethod Method /// - /// /// /// Invoke the named method of the object with the given arguments /// and keyword arguments. Keyword args are passed as a PyDict object. @@ -744,7 +732,6 @@ public PyObject InvokeMethod(string name, PyObject[] args, PyDict kw) /// /// InvokeMethod Method /// - /// /// /// Invoke the named method of the object with the given arguments /// and keyword arguments. Keyword args are passed as a PyDict object. @@ -762,7 +749,6 @@ public PyObject InvokeMethod(string name, PyTuple args, PyDict kw) /// /// IsInstance Method /// - /// /// /// Return true if the object is an instance of the given Python type /// or class. This method always succeeds. @@ -775,14 +761,13 @@ public bool IsInstance(PyObject typeOrClass) Runtime.PyErr_Clear(); return false; } - return (r != 0); + return r != 0; } /// /// IsSubclass Method /// - /// /// /// Return true if the object is identical to or derived from the /// given Python type or class. This method always succeeds. @@ -795,56 +780,52 @@ public bool IsSubclass(PyObject typeOrClass) Runtime.PyErr_Clear(); return false; } - return (r != 0); + return r != 0; } /// /// IsCallable Method /// - /// /// /// Returns true if the object is a callable object. This method /// always succeeds. /// public bool IsCallable() { - return (Runtime.PyCallable_Check(obj) != 0); + return Runtime.PyCallable_Check(obj) != 0; } /// /// IsIterable Method /// - /// /// /// Returns true if the object is iterable object. This method /// always succeeds. /// public bool IsIterable() { - return Runtime.PyIter_Check(obj); + return Runtime.PyObject_IsIterable(obj); } /// /// IsTrue Method /// - /// /// /// Return true if the object is true according to Python semantics. /// This method always succeeds. /// public bool IsTrue() { - return (Runtime.PyObject_IsTrue(obj) != 0); + return Runtime.PyObject_IsTrue(obj) != 0; } /// /// Dir Method /// - /// /// /// Return a list of the names of the attributes of the object. This /// is equivalent to the Python expression "dir(object)". @@ -863,7 +844,6 @@ public PyList Dir() /// /// Repr Method /// - /// /// /// Return a string representation of the object. This method is /// the managed equivalent of the Python expression "repr(object)". @@ -880,7 +860,6 @@ public string Repr() /// /// ToString Method /// - /// /// /// Return the string representation of the object. This method is /// the managed equivalent of the Python expression "str(object)". @@ -897,7 +876,6 @@ public override string ToString() /// /// Equals Method /// - /// /// /// Return true if this object is equal to the given object. This /// method is based on Python equality semantics. @@ -917,14 +895,13 @@ public override bool Equals(object o) { throw new PythonException(); } - return (r == 0); + return r == 0; } /// /// GetHashCode Method /// - /// /// /// Return a hashcode based on the Python object. This returns the /// hash as computed by Python, equivalent to the Python expression @@ -935,61 +912,120 @@ public override int GetHashCode() return Runtime.PyObject_Hash(obj).ToInt32(); } - public override bool TryGetMember(GetMemberBinder binder, out object result) + + public long Refcount { - if (this.HasAttr(binder.Name)) + get { - result = CheckNone(this.GetAttr(binder.Name)); - return true; + return Runtime.Refcount(obj); } - else - return base.TryGetMember(binder, out result); + } + + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + result = CheckNone(this.GetAttr(binder.Name)); + return true; } public override bool TrySetMember(SetMemberBinder binder, object value) { - if (this.HasAttr(binder.Name)) + IntPtr ptr = Converter.ToPython(value, value?.GetType()); + int r = Runtime.PyObject_SetAttrString(obj, binder.Name, ptr); + if (r < 0) { - this.SetAttr(binder.Name, (PyObject)value); - return true; + throw new PythonException(); } - else - return base.TrySetMember(binder, value); + Runtime.XDecref(ptr); + return true; + } + + private void GetArgs(object[] inargs, CallInfo callInfo, out PyTuple args, out PyDict kwargs) + { + if (callInfo == null || callInfo.ArgumentNames.Count == 0) + { + GetArgs(inargs, out args, out kwargs); + return; + } + + // Support for .net named arguments + var namedArgumentCount = callInfo.ArgumentNames.Count; + var regularArgumentCount = callInfo.ArgumentCount - namedArgumentCount; + + var argTuple = Runtime.PyTuple_New(regularArgumentCount); + for (int i = 0; i < regularArgumentCount; ++i) + { + AddArgument(argTuple, i, inargs[i]); + } + args = new PyTuple(argTuple); + + var namedArgs = new object[namedArgumentCount * 2]; + for (int i = 0; i < namedArgumentCount; ++i) + { + namedArgs[i * 2] = callInfo.ArgumentNames[i]; + namedArgs[i * 2 + 1] = inargs[regularArgumentCount + i]; + } + kwargs = Py.kw(namedArgs); } private void GetArgs(object[] inargs, out PyTuple args, out PyDict kwargs) { int arg_count; - for (arg_count = 0; arg_count < inargs.Length && !(inargs[arg_count] is Py.KeywordArguments); ++arg_count) ; + for (arg_count = 0; arg_count < inargs.Length && !(inargs[arg_count] is Py.KeywordArguments); ++arg_count) + { + ; + } IntPtr argtuple = Runtime.PyTuple_New(arg_count); - for (int i = 0; i < arg_count; i++) + for (var i = 0; i < arg_count; i++) { - IntPtr ptr; - if (inargs[i] is PyObject) - { - ptr = ((PyObject)inargs[i]).Handle; - Runtime.XIncref(ptr); - } - else - { - ptr = Converter.ToPython(inargs[i], inargs[i]?.GetType()); - } - if (Runtime.PyTuple_SetItem(argtuple, i, ptr) < 0) - throw new PythonException(); + AddArgument(argtuple, i, inargs[i]); } args = new PyTuple(argtuple); + kwargs = null; for (int i = arg_count; i < inargs.Length; i++) { if (!(inargs[i] is Py.KeywordArguments)) + { throw new ArgumentException("Keyword arguments must come after normal arguments."); + } if (kwargs == null) + { kwargs = (Py.KeywordArguments)inargs[i]; + } else + { kwargs.Update((Py.KeywordArguments)inargs[i]); + } } } + private static void AddArgument(IntPtr argtuple, int i, object target) + { + IntPtr ptr = GetPythonObject(target); + + if (Runtime.PyTuple_SetItem(argtuple, i, ptr) < 0) + { + throw new PythonException(); + } + } + + private static IntPtr GetPythonObject(object target) + { + IntPtr ptr; + if (target is PyObject) + { + ptr = ((PyObject)target).Handle; + Runtime.XIncref(ptr); + } + else + { + ptr = Converter.ToPython(target, target?.GetType()); + } + + return ptr; + } + public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { if (this.HasAttr(binder.Name) && this.GetAttr(binder.Name).IsCallable()) @@ -998,20 +1034,26 @@ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, o PyDict kwargs = null; try { - GetArgs(args, out pyargs, out kwargs); + GetArgs(args, binder.CallInfo, out pyargs, out kwargs); result = CheckNone(InvokeMethod(binder.Name, pyargs, kwargs)); } finally { if (null != pyargs) + { pyargs.Dispose(); + } if (null != kwargs) + { kwargs.Dispose(); + } } return true; } else + { return base.TryInvokeMember(binder, args, out result); + } } public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) @@ -1022,20 +1064,26 @@ public override bool TryInvoke(InvokeBinder binder, object[] args, out object re PyDict kwargs = null; try { - GetArgs(args, out pyargs, out kwargs); + GetArgs(args, binder.CallInfo, out pyargs, out kwargs); result = CheckNone(Invoke(pyargs, kwargs)); } finally { if (null != pyargs) + { pyargs.Dispose(); + } if (null != kwargs) + { kwargs.Dispose(); + } } return true; } else + { return base.TryInvoke(binder, args, out result); + } } public override bool TryConvert(ConvertBinder binder, out object result) @@ -1043,11 +1091,13 @@ public override bool TryConvert(ConvertBinder binder, out object result) return Converter.ToManaged(this.obj, binder.Type, out result, false); } - public override bool TryBinaryOperation(BinaryOperationBinder binder, Object arg, out Object result) + public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) { IntPtr res; if (!(arg is PyObject)) + { arg = arg.ToPython(); + } switch (binder.Operation) { @@ -1152,7 +1202,7 @@ private static object CheckNone(PyObject pyObj) return pyObj; } - public override bool TryUnaryOperation(UnaryOperationBinder binder, out Object result) + public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result) { int r; IntPtr res; @@ -1189,4 +1239,4 @@ public override bool TryUnaryOperation(UnaryOperationBinder binder, out Object r return true; } } -} \ No newline at end of file +} diff --git a/src/runtime/pyscope.cs b/src/runtime/pyscope.cs new file mode 100644 index 000000000..67f93c6e2 --- /dev/null +++ b/src/runtime/pyscope.cs @@ -0,0 +1,657 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Dynamic; + +namespace Python.Runtime +{ + public class PyScopeException : Exception + { + public PyScopeException(string message) + : base(message) + { + + } + } + + /// + /// Classes/methods have this attribute must be used with GIL obtained. + /// + public class PyGILAttribute : Attribute + { + } + + [PyGIL] + public class PyScope : DynamicObject, IDisposable + { + public readonly string Name; + + /// + /// the python Module object the scope associated with. + /// + internal readonly IntPtr obj; + + /// + /// the variable dict of the scope. + /// + internal readonly IntPtr variables; + + private bool _isDisposed; + + /// + /// The Manager this scope associated with. + /// It provides scopes this scope can import. + /// + internal readonly PyScopeManager Manager; + + /// + /// event which will be triggered after the scope disposed. + /// + public event Action OnDispose; + + /// + /// Constructor + /// + /// + /// Create a scope based on a Python Module. + /// + internal PyScope(IntPtr ptr, PyScopeManager manager) + { + if (!Runtime.PyType_IsSubtype(Runtime.PyObject_TYPE(ptr), Runtime.PyModuleType)) + { + throw new PyScopeException("object is not a module"); + } + Manager = manager ?? PyScopeManager.Global; + obj = ptr; + //Refcount of the variables not increase + variables = Runtime.PyModule_GetDict(obj); + Runtime.CheckExceptionOccurred(); + + Runtime.PyDict_SetItemString( + variables, "__builtins__", + Runtime.PyEval_GetBuiltins() + ); + this.Name = this.Get("__name__"); + } + + /// + /// return the variable dict of the scope. + /// + /// + public PyDict Variables() + { + Runtime.XIncref(variables); + return new PyDict(variables); + } + + /// + /// Create a scope, and import all from this scope + /// + /// + public PyScope NewScope() + { + var scope = Manager.Create(); + scope.ImportAll(this); + return scope; + } + + /// + /// Import method + /// + /// + /// Import a scope or a module of given name, + /// scope will be looked up first. + /// + public dynamic Import(string name, string asname = null) + { + Check(); + if (String.IsNullOrEmpty(asname)) + { + asname = name; + } + PyScope scope; + Manager.TryGet(name, out scope); + if (scope != null) + { + Import(scope, asname); + return scope; + } + else + { + PyObject module = PythonEngine.ImportModule(name); + Import(module, asname); + return module; + } + } + + /// + /// Import method + /// + /// + /// Import a scope as a variable of given name. + /// + public void Import(PyScope scope, string asname) + { + this.Set(asname, scope.obj); + } + + /// + /// Import Method + /// + /// + /// The 'import .. as ..' statement in Python. + /// Import a module as a variable into the scope. + /// + public void Import(PyObject module, string asname = null) + { + if (String.IsNullOrEmpty(asname)) + { + asname = module.GetAttr("__name__").As(); + } + Set(asname, module); + } + + /// + /// ImportAll Method + /// + /// + /// The 'import * from ..' statement in Python. + /// Import all content of a scope/module of given name into the scope, scope will be looked up first. + /// + public void ImportAll(string name) + { + PyScope scope; + Manager.TryGet(name, out scope); + if (scope != null) + { + ImportAll(scope); + return; + } + else + { + PyObject module = PythonEngine.ImportModule(name); + ImportAll(module); + } + } + + /// + /// ImportAll Method + /// + /// + /// Import all variables of the scope into this scope. + /// + public void ImportAll(PyScope scope) + { + int result = Runtime.PyDict_Update(variables, scope.variables); + if (result < 0) + { + throw new PythonException(); + } + } + + /// + /// ImportAll Method + /// + /// + /// Import all variables of the module into this scope. + /// + public void ImportAll(PyObject module) + { + if (Runtime.PyObject_Type(module.obj) != Runtime.PyModuleType) + { + throw new PyScopeException("object is not a module"); + } + var module_dict = Runtime.PyModule_GetDict(module.obj); + int result = Runtime.PyDict_Update(variables, module_dict); + if (result < 0) + { + throw new PythonException(); + } + } + + /// + /// ImportAll Method + /// + /// + /// Import all variables in the dictionary into this scope. + /// + public void ImportAll(PyDict dict) + { + int result = Runtime.PyDict_Update(variables, dict.obj); + if (result < 0) + { + throw new PythonException(); + } + } + + /// + /// Execute method + /// + /// + /// Execute a Python ast and return the result as a PyObject. + /// The ast can be either an expression or stmts. + /// + public PyObject Execute(PyObject script, PyDict locals = null) + { + Check(); + IntPtr _locals = locals == null ? variables : locals.obj; + IntPtr ptr = Runtime.PyEval_EvalCode(script.Handle, variables, _locals); + Runtime.CheckExceptionOccurred(); + if (ptr == Runtime.PyNone) + { + Runtime.XDecref(ptr); + return null; + } + return new PyObject(ptr); + } + + /// + /// Execute method + /// + /// + /// Execute a Python ast and return the result as a PyObject, + /// and convert the result to a Managed Object of given type. + /// The ast can be either an expression or stmts. + /// + public T Execute(PyObject script, PyDict locals = null) + { + Check(); + PyObject pyObj = Execute(script, locals); + if (pyObj == null) + { + return default(T); + } + var obj = pyObj.As(); + return obj; + } + + /// + /// Eval method + /// + /// + /// Evaluate a Python expression and return the result as a PyObject + /// or null if an exception is raised. + /// + public PyObject Eval(string code, PyDict locals = null) + { + Check(); + IntPtr _locals = locals == null ? variables : locals.obj; + var flag = (IntPtr)Runtime.Py_eval_input; + IntPtr ptr = Runtime.PyRun_String( + code, flag, variables, _locals + ); + Runtime.CheckExceptionOccurred(); + return new PyObject(ptr); + } + + /// + /// Evaluate a Python expression + /// + /// + /// Evaluate a Python expression + /// and convert the result to a Managed Object of given type. + /// + public T Eval(string code, PyDict locals = null) + { + Check(); + PyObject pyObj = Eval(code, locals); + var obj = pyObj.As(); + return obj; + } + + /// + /// Exec Method + /// + /// + /// Exec a Python script and save its local variables in the current local variable dict. + /// + public void Exec(string code, PyDict locals = null) + { + Check(); + IntPtr _locals = locals == null ? variables : locals.obj; + Exec(code, variables, _locals); + } + + private void Exec(string code, IntPtr _globals, IntPtr _locals) + { + var flag = (IntPtr)Runtime.Py_file_input; + IntPtr ptr = Runtime.PyRun_String( + code, flag, _globals, _locals + ); + Runtime.CheckExceptionOccurred(); + if (ptr != Runtime.PyNone) + { + throw new PythonException(); + } + Runtime.XDecref(ptr); + } + + /// + /// Set Variable Method + /// + /// + /// Add a new variable to the variables dict if it not exist + /// or update its value if the variable exists. + /// + public void Set(string name, object value) + { + IntPtr _value = Converter.ToPython(value, value?.GetType()); + Set(name, _value); + Runtime.XDecref(_value); + } + + private void Set(string name, IntPtr value) + { + Check(); + using (var pyKey = new PyString(name)) + { + int r = Runtime.PyObject_SetItem(variables, pyKey.obj, value); + if (r < 0) + { + throw new PythonException(); + } + } + } + + /// + /// Remove Method + /// + /// + /// Remove a variable from the variables dict. + /// + public void Remove(string name) + { + Check(); + using (var pyKey = new PyString(name)) + { + int r = Runtime.PyObject_DelItem(variables, pyKey.obj); + if (r < 0) + { + throw new PythonException(); + } + } + } + + /// + /// Contains Method + /// + /// + /// Returns true if the variable exists in the scope. + /// + public bool Contains(string name) + { + Check(); + using (var pyKey = new PyString(name)) + { + return Runtime.PyMapping_HasKey(variables, pyKey.obj) != 0; + } + } + + /// + /// Get Method + /// + /// + /// Returns the value of the variable of given name. + /// If the variable does not exist, throw an Exception. + /// + public PyObject Get(string name) + { + PyObject scope; + var state = TryGet(name, out scope); + if (!state) + { + throw new PyScopeException($"The scope of name '{Name}' has no attribute '{name}'"); + } + return scope; + } + + /// + /// TryGet Method + /// + /// + /// Returns the value of the variable, local variable first. + /// If the variable does not exist, return null. + /// + public bool TryGet(string name, out PyObject value) + { + Check(); + using (var pyKey = new PyString(name)) + { + if (Runtime.PyMapping_HasKey(variables, pyKey.obj) != 0) + { + IntPtr op = Runtime.PyObject_GetItem(variables, pyKey.obj); + if (op == IntPtr.Zero) + { + throw new PythonException(); + } + if (op == Runtime.PyNone) + { + Runtime.XDecref(op); + value = null; + return true; + } + value = new PyObject(op); + return true; + } + else + { + value = null; + return false; + } + } + } + + /// + /// Get Method + /// + /// + /// Obtain the value of the variable of given name, + /// and convert the result to a Managed Object of given type. + /// If the variable does not exist, throw an Exception. + /// + public T Get(string name) + { + Check(); + PyObject pyObj = Get(name); + if (pyObj == null) + { + return default(T); + } + return pyObj.As(); + } + + /// + /// TryGet Method + /// + /// + /// Obtain the value of the variable of given name, + /// and convert the result to a Managed Object of given type. + /// If the variable does not exist, return false. + /// + public bool TryGet(string name, out T value) + { + Check(); + PyObject pyObj; + var result = TryGet(name, out pyObj); + if (!result) + { + value = default(T); + return false; + } + if (pyObj == null) + { + if (typeof(T).IsValueType) + { + throw new PyScopeException($"The value of the attribute '{name}' is None which cannot be convert to '{typeof(T).ToString()}'"); + } + else + { + value = default(T); + return true; + } + } + value = pyObj.As(); + return true; + } + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + result = this.Get(binder.Name); + return true; + } + + public override bool TrySetMember(SetMemberBinder binder, object value) + { + this.Set(binder.Name, value); + return true; + } + + private void Check() + { + if (_isDisposed) + { + throw new PyScopeException($"The scope of name '{Name}' object has been disposed"); + } + } + + public void Dispose() + { + if (_isDisposed) + { + return; + } + _isDisposed = true; + Runtime.XDecref(obj); + this.OnDispose?.Invoke(this); + } + + ~PyScope() + { + // We needs to disable Finalizers until it's valid implementation. + // Current implementation can produce low probability floating bugs. + return; + + Dispose(); + } + } + + public class PyScopeManager + { + public readonly static PyScopeManager Global = new PyScopeManager(); + + private Dictionary NamedScopes = new Dictionary(); + + internal PyScope NewScope(string name) + { + if (name == null) + { + name = ""; + } + var module = Runtime.PyModule_New(name); + if (module == IntPtr.Zero) + { + throw new PythonException(); + } + return new PyScope(module, this); + } + + /// + /// Create Method + /// + /// + /// Create an anonymous scope. + /// + [PyGIL] + public PyScope Create() + { + var scope = this.NewScope(null); + return scope; + } + + /// + /// Create Method + /// + /// + /// Create an named scope of given name. + /// + [PyGIL] + public PyScope Create(string name) + { + if (String.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(nameof(name)); + } + if (name != null && Contains(name)) + { + throw new PyScopeException($"A scope of name '{name}' does already exist"); + } + var scope = this.NewScope(name); + scope.OnDispose += Remove; + NamedScopes[name] = scope; + return scope; + } + + /// + /// Contains Method + /// + /// + /// return true if the scope exists in this manager. + /// + public bool Contains(string name) + { + return NamedScopes.ContainsKey(name); + } + + /// + /// Get Method + /// + /// + /// Find the scope in this manager. + /// If the scope not exist, an Exception will be thrown. + /// + public PyScope Get(string name) + { + if (String.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(nameof(name)); + } + if (NamedScopes.ContainsKey(name)) + { + return NamedScopes[name]; + } + throw new PyScopeException($"There is no scope named '{name}' registered in this manager"); + } + + /// + /// Get Method + /// + /// + /// Try to find the scope in this manager. + /// + public bool TryGet(string name, out PyScope scope) + { + return NamedScopes.TryGetValue(name, out scope); + } + + /// + /// Remove Method + /// + /// + /// remove the scope from this manager. + /// + public void Remove(PyScope scope) + { + NamedScopes.Remove(scope.Name); + } + + [PyGIL] + public void Clear() + { + var scopes = NamedScopes.Values.ToList(); + foreach (var scope in scopes) + { + scope.Dispose(); + } + } + } +} diff --git a/src/runtime/pysequence.cs b/src/runtime/pysequence.cs index d32921901..bfaee79a6 100644 --- a/src/runtime/pysequence.cs +++ b/src/runtime/pysequence.cs @@ -6,7 +6,9 @@ namespace Python.Runtime /// /// Represents a generic Python sequence. The methods of this class are /// equivalent to the Python "abstract sequence API". See - /// http://www.python.org/doc/current/api/sequence.html for details. + /// PY2: https://docs.python.org/2/c-api/sequence.html + /// PY3: https://docs.python.org/3/c-api/sequence.html + /// for details. /// public class PySequence : PyObject, IEnumerable { @@ -14,7 +16,7 @@ protected PySequence(IntPtr ptr) : base(ptr) { } - protected PySequence() : base() + protected PySequence() { } @@ -22,7 +24,6 @@ protected PySequence() : base() /// /// IsSequenceType Method /// - /// /// /// Returns true if the given object implements the sequence protocol. /// @@ -35,7 +36,6 @@ public static bool IsSequenceType(PyObject value) /// /// GetSlice Method /// - /// /// /// Return the slice of the sequence with the given indices. /// @@ -53,7 +53,6 @@ public PyObject GetSlice(int i1, int i2) /// /// SetSlice Method /// - /// /// /// Sets the slice of the sequence with the given indices. /// @@ -70,7 +69,6 @@ public void SetSlice(int i1, int i2, PyObject v) /// /// DelSlice Method /// - /// /// /// Deletes the slice of the sequence with the given indices. /// @@ -87,7 +85,6 @@ public void DelSlice(int i1, int i2) /// /// Index Method /// - /// /// /// Return the index of the given item in the sequence, or -1 if /// the item does not appear in the sequence. @@ -107,7 +104,6 @@ public int Index(PyObject item) /// /// Contains Method /// - /// /// /// Return true if the sequence contains the given item. This method /// throws a PythonException if an error occurs during the check. @@ -119,14 +115,13 @@ public bool Contains(PyObject item) { throw new PythonException(); } - return (r != 0); + return r != 0; } /// /// Concat Method /// - /// /// /// Return the concatenation of the sequence object with the passed in /// sequence object. @@ -145,7 +140,6 @@ public PyObject Concat(PyObject other) /// /// Repeat Method /// - /// /// /// Return the sequence object repeated N times. This is equivalent /// to the Python expression "object * count". @@ -160,4 +154,4 @@ public PyObject Repeat(int count) return new PyObject(op); } } -} \ No newline at end of file +} diff --git a/src/runtime/pystring.cs b/src/runtime/pystring.cs index 46b8fd657..c9c4f9f5b 100644 --- a/src/runtime/pystring.cs +++ b/src/runtime/pystring.cs @@ -3,16 +3,19 @@ namespace Python.Runtime { /// - /// Represents a Python (ansi) string object. See the documentation at - /// http://www.python.org/doc/current/api/stringObjects.html for details. - /// 2011-01-29: ...Then why does the string constructor call PyUnicode_FromUnicode()??? + /// Represents a Python (ANSI) string object. See the documentation at + /// PY2: https://docs.python.org/2/c-api/string.html + /// PY3: No Equivalent + /// for details. /// + /// + /// 2011-01-29: ...Then why does the string constructor call PyUnicode_FromUnicode()??? + /// public class PyString : PySequence { /// /// PyString Constructor /// - /// /// /// Creates a new PyString from an existing object reference. Note /// that the instance assumes ownership of the object reference. @@ -26,13 +29,12 @@ public PyString(IntPtr ptr) : base(ptr) /// /// PyString Constructor /// - /// /// /// Copy constructor - obtain a PyString from a generic PyObject. /// An ArgumentException will be thrown if the given object is not /// a Python string object. /// - public PyString(PyObject o) : base() + public PyString(PyObject o) { if (!IsStringType(o)) { @@ -46,24 +48,19 @@ public PyString(PyObject o) : base() /// /// PyString Constructor /// - /// /// /// Creates a Python string from a managed string. /// - public PyString(string s) : base() + public PyString(string s) { obj = Runtime.PyUnicode_FromUnicode(s, s.Length); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); } /// /// IsStringType Method /// - /// /// /// Returns true if the given object is a Python string. /// @@ -72,4 +69,4 @@ public static bool IsStringType(PyObject value) return Runtime.PyString_Check(value.obj); } } -} \ No newline at end of file +} diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs index 4c676d375..a23c7ac79 100644 --- a/src/runtime/pythonengine.cs +++ b/src/runtime/pythonengine.cs @@ -1,19 +1,42 @@ -using System; +using System; +using System.Collections.Generic; using System.IO; -using System.Threading; +using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; namespace Python.Runtime { /// /// This class provides the public interface of the Python runtime. /// - public class PythonEngine + public class PythonEngine : IDisposable { private static DelegateManager delegateManager; private static bool initialized; + private static IntPtr _pythonHome = IntPtr.Zero; + private static IntPtr _programName = IntPtr.Zero; + private static IntPtr _pythonPath = IntPtr.Zero; - #region Properties + public PythonEngine() + { + Initialize(); + } + + public PythonEngine(params string[] args) + { + Initialize(args); + } + + public PythonEngine(IEnumerable args) + { + Initialize(args); + } + + public void Dispose() + { + Shutdown(); + } public static bool IsInitialized { @@ -37,62 +60,74 @@ public static string ProgramName { get { - string result = Runtime.Py_GetProgramName(); - if (result == null) - { - return ""; - } - return result; + IntPtr p = Runtime.Py_GetProgramName(); + return UcsMarshaler.PtrToPy3UnicodePy2String(p) ?? ""; + } + set + { + Marshal.FreeHGlobal(_programName); + _programName = UcsMarshaler.Py3UnicodePy2StringtoPtr(value); + Runtime.Py_SetProgramName(_programName); } - set { Runtime.Py_SetProgramName(value); } } public static string PythonHome { get { - string result = Runtime.Py_GetPythonHome(); - if (result == null) - { - return ""; - } - return result; + IntPtr p = Runtime.Py_GetPythonHome(); + return UcsMarshaler.PtrToPy3UnicodePy2String(p) ?? ""; + } + set + { + Marshal.FreeHGlobal(_pythonHome); + _pythonHome = UcsMarshaler.Py3UnicodePy2StringtoPtr(value); + Runtime.Py_SetPythonHome(_pythonHome); } - set { Runtime.Py_SetPythonHome(value); } } public static string PythonPath { get { - string result = Runtime.Py_GetPath(); - if (result == null) + IntPtr p = Runtime.Py_GetPath(); + return UcsMarshaler.PtrToPy3UnicodePy2String(p) ?? ""; + } + set + { + if (Runtime.IsPython2) { - return ""; + throw new NotSupportedException("Set PythonPath not supported on Python 2"); } - return result; + Marshal.FreeHGlobal(_pythonPath); + _pythonPath = UcsMarshaler.Py3UnicodePy2StringtoPtr(value); + Runtime.Py_SetPath(_pythonPath); } - set { Runtime.Py_SetPath(value); } } public static string Version { - get { return Runtime.Py_GetVersion(); } + get { return Marshal.PtrToStringAnsi(Runtime.Py_GetVersion()); } } public static string BuildInfo { - get { return Runtime.Py_GetBuildInfo(); } + get { return Marshal.PtrToStringAnsi(Runtime.Py_GetBuildInfo()); } } public static string Platform { - get { return Runtime.Py_GetPlatform(); } + get { return Marshal.PtrToStringAnsi(Runtime.Py_GetPlatform()); } } public static string Copyright { - get { return Runtime.Py_GetCopyright(); } + get { return Marshal.PtrToStringAnsi(Runtime.Py_GetCopyright()); } + } + + public static string Compiler + { + get { return Marshal.PtrToStringAnsi(Runtime.Py_GetCompiler()); } } public static int RunSimpleString(string code) @@ -100,19 +135,26 @@ public static int RunSimpleString(string code) return Runtime.PyRun_SimpleString(code); } - #endregion + public static void Initialize() + { + Initialize(setSysArgv: true); + } + + public static void Initialize(bool setSysArgv = true) + { + Initialize(Enumerable.Empty(), setSysArgv: setSysArgv); + } /// /// Initialize Method /// - /// /// /// Initialize the Python runtime. It is safe to call this method /// more than once, though initialization will only happen on the /// first call. It is *not* necessary to hold the Python global /// interpreter lock (GIL) to call this method. /// - public static void Initialize() + public static void Initialize(IEnumerable args, bool setSysArgv = true) { if (!initialized) { @@ -126,21 +168,24 @@ public static void Initialize() initialized = true; Exceptions.Clear(); + if (setSysArgv) + { + Py.SetArgv(args); + } + // register the atexit callback (this doesn't use Py_AtExit as the C atexit // callbacks are called after python is fully finalized but the python ones // are called while the python engine is still running). string code = "import atexit, clr\n" + "atexit.register(clr._AtExit)\n"; - PyObject r = PythonEngine.RunString(code); - if (r != null) - r.Dispose(); + PythonEngine.Exec(code); // Load the clr.py resource into the clr module IntPtr clr = Python.Runtime.ImportHook.GetCLRModule(); IntPtr clr_dict = Runtime.PyModule_GetDict(clr); - PyDict locals = new PyDict(); + var locals = new PyDict(); try { IntPtr module = Runtime.PyImport_AddModule("clr._extras"); @@ -148,16 +193,13 @@ public static void Initialize() IntPtr builtins = Runtime.PyEval_GetBuiltins(); Runtime.PyDict_SetItemString(module_globals, "__builtins__", builtins); - var assembly = Assembly.GetExecutingAssembly(); + Assembly assembly = Assembly.GetExecutingAssembly(); using (Stream stream = assembly.GetManifestResourceStream("clr.py")) - using (StreamReader reader = new StreamReader(stream)) + using (var reader = new StreamReader(stream)) { // add the contents of clr.py to the module string clr_py = reader.ReadToEnd(); - PyObject result = RunString(clr_py, module_globals, locals.Handle); - if (null == result) - throw new PythonException(); - result.Dispose(); + Exec(clr_py, module_globals, locals.Handle); } // add the imported module to the clr module, and copy the API functions @@ -181,20 +223,20 @@ public static void Initialize() } } - //==================================================================== - // A helper to perform initialization from the context of an active - // CPython interpreter process - this bootstraps the managed runtime - // when it is imported by the CLR extension module. - //==================================================================== + /// + /// A helper to perform initialization from the context of an active + /// CPython interpreter process - this bootstraps the managed runtime + /// when it is imported by the CLR extension module. + /// #if PYTHON3 - public static IntPtr InitExt() { + public static IntPtr InitExt() #elif PYTHON2 public static void InitExt() - { #endif + { try { - Initialize(); + Initialize(setSysArgv: false); // Trickery - when the import hook is installed into an already // running Python, the standard import machinery is still in @@ -225,11 +267,7 @@ public static void InitExt() " exec(line)\n" + " break\n"; - PyObject r = PythonEngine.RunString(code); - if (r != null) - { - r.Dispose(); - } + PythonEngine.Exec(code); } catch (PythonException e) { @@ -247,7 +285,6 @@ public static void InitExt() /// /// Shutdown Method /// - /// /// /// Shutdown and release resources held by the Python runtime. The /// Python runtime can no longer be used in the current process @@ -257,6 +294,14 @@ public static void Shutdown() { if (initialized) { + PyScopeManager.Global.Clear(); + Marshal.FreeHGlobal(_pythonHome); + _pythonHome = IntPtr.Zero; + Marshal.FreeHGlobal(_programName); + _programName = IntPtr.Zero; + Marshal.FreeHGlobal(_pythonPath); + _pythonPath = IntPtr.Zero; + Runtime.Shutdown(); initialized = false; } @@ -266,17 +311,14 @@ public static void Shutdown() /// /// AcquireLock Method /// - /// /// /// Acquire the Python global interpreter lock (GIL). Managed code /// *must* call this method before using any objects or calling any /// methods on objects in the Python.Runtime namespace. The only /// exception is PythonEngine.Initialize, which may be called without /// first calling AcquireLock. - /// /// Each call to AcquireLock must be matched by a corresponding call /// to ReleaseLock, passing the token obtained from AcquireLock. - /// /// For more information, see the "Extending and Embedding" section /// of the Python documentation on www.python.org. /// @@ -289,11 +331,9 @@ public static IntPtr AcquireLock() /// /// ReleaseLock Method /// - /// /// /// Release the Python global interpreter lock using a token obtained /// from a previous call to AcquireLock. - /// /// For more information, see the "Extending and Embedding" section /// of the Python documentation on www.python.org. /// @@ -306,12 +346,10 @@ public static void ReleaseLock(IntPtr gs) /// /// BeginAllowThreads Method /// - /// /// /// Release the Python global interpreter lock to allow other threads /// to run. This is equivalent to the Py_BEGIN_ALLOW_THREADS macro /// provided by the C Python API. - /// /// For more information, see the "Extending and Embedding" section /// of the Python documentation on www.python.org. /// @@ -324,12 +362,10 @@ public static IntPtr BeginAllowThreads() /// /// EndAllowThreads Method /// - /// /// /// Re-aquire the Python global interpreter lock for the current /// thread. This is equivalent to the Py_END_ALLOW_THREADS macro /// provided by the C Python API. - /// /// For more information, see the "Extending and Embedding" section /// of the Python documentation on www.python.org. /// @@ -342,7 +378,6 @@ public static void EndAllowThreads(IntPtr ts) /// /// ImportModule Method /// - /// /// /// Given a fully-qualified module or package name, import the /// module and return the resulting module object as a PyObject @@ -351,10 +386,7 @@ public static void EndAllowThreads(IntPtr ts) public static PyObject ImportModule(string name) { IntPtr op = Runtime.PyImport_ImportModule(name); - if (op == IntPtr.Zero) - { - return null; - } + Runtime.CheckExceptionOccurred(); return new PyObject(op); } @@ -362,7 +394,6 @@ public static PyObject ImportModule(string name) /// /// ReloadModule Method /// - /// /// /// Given a PyObject representing a previously loaded module, reload /// the module. @@ -370,10 +401,7 @@ public static PyObject ImportModule(string name) public static PyObject ReloadModule(PyObject module) { IntPtr op = Runtime.PyImport_ReloadModule(module.Handle); - if (op == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); return new PyObject(op); } @@ -381,7 +409,6 @@ public static PyObject ReloadModule(PyObject module) /// /// ModuleFromString Method /// - /// /// /// Given a string module name and a string containing Python code, /// execute the code in and return a module of the given name. @@ -389,68 +416,143 @@ public static PyObject ReloadModule(PyObject module) public static PyObject ModuleFromString(string name, string code) { IntPtr c = Runtime.Py_CompileString(code, "none", (IntPtr)257); - if (c == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); IntPtr m = Runtime.PyImport_ExecCodeModule(name, c); - if (m == IntPtr.Zero) + Runtime.CheckExceptionOccurred(); + return new PyObject(m); + } + + public static PyObject Compile(string code, string filename = "", RunFlagType mode = RunFlagType.File) + { + var flag = (IntPtr)mode; + IntPtr ptr = Runtime.Py_CompileString(code, filename, flag); + Runtime.CheckExceptionOccurred(); + return new PyObject(ptr); + } + + /// + /// Eval Method + /// + /// + /// Evaluate a Python expression and returns the result. + /// It's a subset of Python eval function. + /// + public static PyObject Eval(string code, IntPtr? globals = null, IntPtr? locals = null) + { + PyObject result = RunString(code, globals, locals, RunFlagType.Eval); + return result; + } + + + /// + /// Exec Method + /// + /// + /// Run a string containing Python code. + /// It's a subset of Python exec function. + /// + public static void Exec(string code, IntPtr? globals = null, IntPtr? locals = null) + { + PyObject result = RunString(code, globals, locals, RunFlagType.File); + if (result.obj != Runtime.PyNone) { throw new PythonException(); } - return new PyObject(m); + result.Dispose(); } /// - /// RunString Method + /// RunString Method. Function has been deprecated and will be removed. + /// Use Exec/Eval/RunSimpleString instead. + /// + [Obsolete("RunString is deprecated and will be removed. Use Exec/Eval/RunSimpleString instead.")] + public static PyObject RunString(string code, IntPtr? globals = null, IntPtr? locals = null) + { + return RunString(code, globals, locals, RunFlagType.File); + } + + /// + /// Internal RunString Method. /// - /// /// /// Run a string containing Python code. Returns the result of /// executing the code string as a PyObject instance, or null if /// an exception was raised. /// - public static PyObject RunString(string code) + internal static PyObject RunString(string code, IntPtr? globals, IntPtr? locals, RunFlagType flag) { - IntPtr globals = Runtime.PyEval_GetGlobals(); - IntPtr locals = Runtime.PyDict_New(); - - IntPtr builtins = Runtime.PyEval_GetBuiltins(); - Runtime.PyDict_SetItemString(locals, "__builtins__", builtins); - - IntPtr flag = (IntPtr)257; /* Py_file_input */ - IntPtr result = Runtime.PyRun_String(code, flag, globals, locals); - Runtime.XDecref(locals); - if (result == IntPtr.Zero) + var borrowedGlobals = true; + if (globals == null) { - return null; + globals = Runtime.PyEval_GetGlobals(); + if (globals == IntPtr.Zero) + { + globals = Runtime.PyDict_New(); + Runtime.PyDict_SetItemString( + globals.Value, "__builtins__", + Runtime.PyEval_GetBuiltins() + ); + borrowedGlobals = false; + } + } + + if (locals == null) + { + locals = globals; } - return new PyObject(result); - } - public static PyObject RunString(string code, IntPtr globals, IntPtr locals) - { - IntPtr flag = (IntPtr)257; /* Py_file_input */ - IntPtr result = Runtime.PyRun_String(code, flag, globals, locals); - if (result == IntPtr.Zero) + try { - return null; + IntPtr result = Runtime.PyRun_String( + code, (IntPtr)flag, globals.Value, locals.Value + ); + + Runtime.CheckExceptionOccurred(); + + return new PyObject(result); + } + finally + { + if (!borrowedGlobals) + { + Runtime.XDecref(globals.Value); + } } - return new PyObject(result); } } + public enum RunFlagType + { + Single = 256, + File = 257, /* Py_file_input */ + Eval = 258 + } + public static class Py { public static GILState GIL() { if (!PythonEngine.IsInitialized) + { PythonEngine.Initialize(); + } return new GILState(); } + public static PyScope CreateScope() + { + var scope = PyScopeManager.Global.Create(); + return scope; + } + + public static PyScope CreateScope(string name) + { + var scope = PyScopeManager.Global.Create(name); + return scope; + } + public class GILState : IDisposable { private IntPtr state; @@ -479,19 +581,29 @@ public class KeywordArguments : PyDict public static KeywordArguments kw(params object[] kv) { var dict = new KeywordArguments(); - if (kv.Length%2 != 0) + if (kv.Length % 2 != 0) + { throw new ArgumentException("Must have an equal number of keys and values"); - for (int i = 0; i < kv.Length; i += 2) + } + for (var i = 0; i < kv.Length; i += 2) { IntPtr value; if (kv[i + 1] is PyObject) + { value = ((PyObject)kv[i + 1]).Handle; + } else + { value = Converter.ToPython(kv[i + 1], kv[i + 1]?.GetType()); + } if (Runtime.PyDict_SetItemString(dict.Handle, (string)kv[i], value) != 0) + { throw new ArgumentException(string.Format("Cannot add key '{0}' to dictionary.", (string)kv[i])); + } if (!(kv[i + 1] is PyObject)) + { Runtime.XDecref(value); + } } return dict; } @@ -500,5 +612,68 @@ public static PyObject Import(string name) { return PythonEngine.ImportModule(name); } + + public static void SetArgv() + { + IEnumerable args; + try + { + args = Environment.GetCommandLineArgs(); + } + catch (NotSupportedException) + { + args = Enumerable.Empty(); + } + + SetArgv( + new[] { "" }.Concat( + Environment.GetCommandLineArgs().Skip(1) + ) + ); + } + + public static void SetArgv(params string[] argv) + { + SetArgv(argv as IEnumerable); + } + + public static void SetArgv(IEnumerable argv) + { + using (GIL()) + { + string[] arr = argv.ToArray(); + Runtime.PySys_SetArgvEx(arr.Length, arr, 0); + Runtime.CheckExceptionOccurred(); + } + } + + public static void With(PyObject obj, Action Body) + { + // Behavior described here: + // https://docs.python.org/2/reference/datamodel.html#with-statement-context-managers + + IntPtr type = Runtime.PyNone; + IntPtr val = Runtime.PyNone; + IntPtr traceBack = Runtime.PyNone; + PythonException ex = null; + + try + { + PyObject enterResult = obj.InvokeMethod("__enter__"); + + Body(enterResult); + } + catch (PythonException e) + { + ex = e; + type = ex.PyType; + val = ex.PyValue; + traceBack = ex.PyTB; + } + + var exitResult = obj.InvokeMethod("__exit__", new PyObject(type), new PyObject(val), new PyObject(traceBack)); + + if (ex != null && !exitResult.IsTrue()) throw ex; + } } } diff --git a/src/runtime/pythonexception.cs b/src/runtime/pythonexception.cs index 2999432c1..ded7fbeb5 100644 --- a/src/runtime/pythonexception.cs +++ b/src/runtime/pythonexception.cs @@ -13,28 +13,31 @@ public class PythonException : System.Exception private IntPtr _pyTB = IntPtr.Zero; private string _tb = ""; private string _message = ""; + private string _pythonTypeName = ""; private bool disposed = false; - public PythonException() : base() + public PythonException() { IntPtr gs = PythonEngine.AcquireLock(); Runtime.PyErr_Fetch(ref _pyType, ref _pyValue, ref _pyTB); Runtime.XIncref(_pyType); Runtime.XIncref(_pyValue); Runtime.XIncref(_pyTB); - if ((_pyType != IntPtr.Zero) && (_pyValue != IntPtr.Zero)) + if (_pyType != IntPtr.Zero && _pyValue != IntPtr.Zero) { string type; string message; Runtime.XIncref(_pyType); - using (PyObject pyType = new PyObject(_pyType)) + using (var pyType = new PyObject(_pyType)) using (PyObject pyTypeName = pyType.GetAttr("__name__")) { type = pyTypeName.ToString(); } + _pythonTypeName = type; + Runtime.XIncref(_pyValue); - using (PyObject pyValue = new PyObject(_pyValue)) + using (var pyValue = new PyObject(_pyValue)) { message = pyValue.ToString(); } @@ -44,7 +47,7 @@ public PythonException() : base() { PyObject tb_module = PythonEngine.ImportModule("traceback"); Runtime.XIncref(_pyTB); - using (PyObject pyTB = new PyObject(_pyTB)) + using (var pyTB = new PyObject(_pyTB)) { _tb = tb_module.InvokeMethod("format_tb", pyTB).ToString(); } @@ -57,6 +60,10 @@ public PythonException() : base() ~PythonException() { + // We needs to disable Finalizers until it's valid implementation. + // Current implementation can produce low probability floating bugs. + return; + Dispose(); } @@ -76,7 +83,6 @@ public void Restore() /// /// PyType Property /// - /// /// /// Returns the exception type as a Python object. /// @@ -88,7 +94,6 @@ public IntPtr PyType /// /// PyValue Property /// - /// /// /// Returns the exception value as a Python object. /// @@ -100,7 +105,6 @@ public IntPtr PyValue /// /// PyTB Property /// - /// /// /// Returns the TraceBack as a Python object. /// @@ -112,7 +116,6 @@ public IntPtr PyTB /// /// Message Property /// - /// /// /// A string representing the python exception message. /// @@ -124,7 +127,6 @@ public override string Message /// /// StackTrace Property /// - /// /// /// A string representing the python exception stack trace. /// @@ -133,20 +135,28 @@ public override string StackTrace get { return _tb; } } + /// + /// Python error type name. + /// + public string PythonTypeName + { + get { return _pythonTypeName; } + } /// /// Dispose Method /// - /// /// /// The Dispose method provides a way to explicitly release the /// Python objects represented by a PythonException. + /// If object not properly disposed can cause AppDomain unload issue. + /// See GH#397 and GH#400. /// public void Dispose() { if (!disposed) { - if (Runtime.Py_IsInitialized() > 0) + if (Runtime.Py_IsInitialized() > 0 && !Runtime.IsFinalizing) { IntPtr gs = PythonEngine.AcquireLock(); Runtime.XDecref(_pyType); @@ -166,7 +176,6 @@ public void Dispose() /// /// Matches Method /// - /// /// /// Returns true if the Python exception type represented by the /// PythonException instance matches the given exception type. @@ -176,4 +185,4 @@ public static bool Matches(IntPtr ob) return Runtime.PyErr_ExceptionMatches(ob) != 0; } } -} \ No newline at end of file +} diff --git a/src/runtime/pytuple.cs b/src/runtime/pytuple.cs index 123ad4359..45f3d8350 100644 --- a/src/runtime/pytuple.cs +++ b/src/runtime/pytuple.cs @@ -4,14 +4,15 @@ namespace Python.Runtime { /// /// Represents a Python tuple object. See the documentation at - /// http://www.python.org/doc/current/api/tupleObjects.html for details. + /// PY2: https://docs.python.org/2/c-api/tupleObjects.html + /// PY3: https://docs.python.org/3/c-api/tupleObjects.html + /// for details. /// public class PyTuple : PySequence { /// /// PyTuple Constructor /// - /// /// /// Creates a new PyTuple from an existing object reference. Note /// that the instance assumes ownership of the object reference. @@ -25,13 +26,12 @@ public PyTuple(IntPtr ptr) : base(ptr) /// /// PyTuple Constructor /// - /// /// /// Copy constructor - obtain a PyTuple from a generic PyObject. An /// ArgumentException will be thrown if the given object is not a /// Python tuple object. /// - public PyTuple(PyObject o) : base() + public PyTuple(PyObject o) { if (!IsTupleType(o)) { @@ -45,40 +45,35 @@ public PyTuple(PyObject o) : base() /// /// PyTuple Constructor /// - /// /// /// Creates a new empty PyTuple. /// - public PyTuple() : base() + public PyTuple() { obj = Runtime.PyTuple_New(0); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); } /// /// PyTuple Constructor /// - /// /// /// Creates a new PyTuple from an array of PyObject instances. + /// + /// See caveats about PyTuple_SetItem: + /// https://www.coursehero.com/file/p4j2ogg/important-exceptions-to-this-rule-PyTupleSetItem-and-PyListSetItem-These/ /// - public PyTuple(PyObject[] items) : base() + public PyTuple(PyObject[] items) { int count = items.Length; obj = Runtime.PyTuple_New(count); - for (int i = 0; i < count; i++) + for (var i = 0; i < count; i++) { IntPtr ptr = items[i].obj; Runtime.XIncref(ptr); - int r = Runtime.PyTuple_SetItem(obj, i, ptr); - if (r < 0) - { - throw new PythonException(); - } + Runtime.PyTuple_SetItem(obj, i, ptr); + Runtime.CheckExceptionOccurred(); } } @@ -86,7 +81,6 @@ public PyTuple(PyObject[] items) : base() /// /// IsTupleType Method /// - /// /// /// Returns true if the given object is a Python tuple. /// @@ -99,7 +93,6 @@ public static bool IsTupleType(PyObject value) /// /// AsTuple Method /// - /// /// /// Convert a Python object to a Python tuple if possible, raising /// a PythonException if the conversion is not possible. This is @@ -108,11 +101,8 @@ public static bool IsTupleType(PyObject value) public static PyTuple AsTuple(PyObject value) { IntPtr op = Runtime.PySequence_Tuple(value.obj); - if (op == IntPtr.Zero) - { - throw new PythonException(); - } + Runtime.CheckExceptionOccurred(); return new PyTuple(op); } } -} \ No newline at end of file +} diff --git a/src/runtime/resources/clr.py b/src/runtime/resources/clr.py index c329b1f6d..e708a54ac 100644 --- a/src/runtime/resources/clr.py +++ b/src/runtime/resources/clr.py @@ -2,7 +2,7 @@ Code in this module gets loaded into the main clr module. """ -__version__ = "2.2.2" +__version__ = "2.4.0.dev0" class clrproperty(object): diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 80f62df49..abd0661a4 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -1,351 +1,338 @@ using System; using System.Runtime.InteropServices; using System.Security; -#if (UCS4) using System.Text; -using Mono.Unix; - -#endif - -#if (UCS2 && PYTHON3) -using System.Text; -#endif namespace Python.Runtime { - [SuppressUnmanagedCodeSecurityAttribute()] - static class NativeMethods + [SuppressUnmanagedCodeSecurity] + internal static class NativeMethods { -#if (MONO_LINUX || MONO_OSX) - static public IntPtr LoadLibrary(string fileName) { +#if MONO_LINUX || MONO_OSX +#if NETSTANDARD + private static int RTLD_NOW = 0x2; +#if MONO_LINUX + private static int RTLD_GLOBAL = 0x100; + private static IntPtr RTLD_DEFAULT = IntPtr.Zero; + private const string NativeDll = "libdl.so"; + public static IntPtr LoadLibrary(string fileName) + { + return dlopen($"lib{fileName}.so", RTLD_NOW | RTLD_GLOBAL); + } +#elif MONO_OSX + private static int RTLD_GLOBAL = 0x8; + private const string NativeDll = "/usr/lib/libSystem.dylib" + private static IntPtr RTLD_DEFAULT = new IntPtr(-2); + + public static IntPtr LoadLibrary(string fileName) + { + return dlopen($"lib{fileName}.dylib", RTLD_NOW | RTLD_GLOBAL); + } +#endif +#else + private static int RTLD_NOW = 0x2; + private static int RTLD_SHARED = 0x20; +#if MONO_OSX + private static IntPtr RTLD_DEFAULT = new IntPtr(-2); + private const string NativeDll = "__Internal"; +#elif MONO_LINUX + private static IntPtr RTLD_DEFAULT = IntPtr.Zero; + private const string NativeDll = "libdl.so"; +#endif + + public static IntPtr LoadLibrary(string fileName) + { return dlopen(fileName, RTLD_NOW | RTLD_SHARED); } +#endif + - static public void FreeLibrary(IntPtr handle) { + public static void FreeLibrary(IntPtr handle) + { dlclose(handle); } - static public IntPtr GetProcAddress(IntPtr dllHandle, string name) { + public static IntPtr GetProcAddress(IntPtr dllHandle, string name) + { // look in the exe if dllHandle is NULL - if (IntPtr.Zero == dllHandle) + if (dllHandle == IntPtr.Zero) + { dllHandle = RTLD_DEFAULT; + } // clear previous errors if any dlerror(); - var res = dlsym(dllHandle, name); - var errPtr = dlerror(); - if (errPtr != IntPtr.Zero) { + IntPtr res = dlsym(dllHandle, name); + IntPtr errPtr = dlerror(); + if (errPtr != IntPtr.Zero) + { throw new Exception("dlsym: " + Marshal.PtrToStringAnsi(errPtr)); } return res; } -#if (MONO_OSX) - static int RTLD_NOW = 0x2; - static int RTLD_SHARED = 0x20; - static IntPtr RTLD_DEFAULT = new IntPtr(-2); + [DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + public static extern IntPtr dlopen(String fileName, int flags); - [DllImport("__Internal")] - private static extern IntPtr dlopen(String fileName, int flags); - - [DllImport("__Internal")] + [DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] private static extern IntPtr dlsym(IntPtr handle, String symbol); - [DllImport("__Internal")] + [DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)] private static extern int dlclose(IntPtr handle); - [DllImport("__Internal")] + [DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr dlerror(); -#else - static int RTLD_NOW = 0x2; - static int RTLD_SHARED = 0x20; - static IntPtr RTLD_DEFAULT = IntPtr.Zero; - - [DllImport("libdl.so")] - private static extern IntPtr dlopen(String fileName, int flags); +#else // Windows + private const string NativeDll = "kernel32.dll"; - [DllImport("libdl.so")] - private static extern IntPtr dlsym(IntPtr handle, String symbol); - - [DllImport("libdl.so")] - private static extern int dlclose(IntPtr handle); - - [DllImport("libdl.so")] - private static extern IntPtr dlerror(); -#endif - -#else - [DllImport("kernel32.dll")] + [DllImport(NativeDll)] public static extern IntPtr LoadLibrary(string dllToLoad); - [DllImport("kernel32.dll")] + [DllImport(NativeDll)] public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); - [DllImport("kernel32.dll")] + [DllImport(NativeDll)] public static extern bool FreeLibrary(IntPtr hModule); #endif } + /// + /// Encapsulates the low-level Python C API. Note that it is + /// the responsibility of the caller to have acquired the GIL + /// before calling any of these methods. + /// public class Runtime { + // C# compiler copies constants to the assemblies that references this library. + // We needs to replace all public constants to static readonly fields to allow + // binary substitution of different Python.Runtime.dll builds in a target application. + + public static int UCS => _UCS; + +#if UCS4 + internal const int _UCS = 4; + /// - /// Encapsulates the low-level Python C API. Note that it is - /// the responsibility of the caller to have acquired the GIL - /// before calling any of these methods. + /// EntryPoint to be used in DllImport to map to correct Unicode + /// methods prior to PEP393. Only used for PY27. /// -#if (UCS4) - public const int UCS = 4; -#endif -#if (UCS2) - public const int UCS = 2; -#endif -#if ! (UCS2 || UCS4) -#error You must define either UCS2 or UCS4! -#endif + private const string PyUnicodeEntryPoint = "PyUnicodeUCS4_"; +#elif UCS2 + internal const int _UCS = 2; -#if (PYTHON23) - public const string pyversion = "2.3"; - public const int pyversionnumber = 23; -#endif -#if (PYTHON24) - public const string pyversion = "2.4"; - public const int pyversionnumber = 24; -#endif -#if (PYTHON25) - public const string pyversion = "2.5"; - public const int pyversionnumber = 25; -#endif -#if (PYTHON26) - public const string pyversion = "2.6"; - public const int pyversionnumber = 26; -#endif -#if (PYTHON27) - public const string pyversion = "2.7"; - public const int pyversionnumber = 27; -#endif -#if (PYTHON32) - public const string pyversion = "3.2"; - public const int pyversionnumber = 32; -#endif -#if (PYTHON33) - public const string pyversion = "3.3"; - public const int pyversionnumber = 33; -#endif -#if (PYTHON34) - public const string pyversion = "3.4"; - public const int pyversionnumber = 34; -#endif -#if (PYTHON35) - public const string pyversion = "3.5"; - public const int pyversionnumber = 35; -#endif -#if (PYTHON36) - public const string pyversion = "3.6"; - public const int pyversionnumber = 36; -#endif -#if ! (PYTHON23 || PYTHON24 || PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35 || PYTHON36) -#error You must define one of PYTHON23 to PYTHON36 + /// + /// EntryPoint to be used in DllImport to map to correct Unicode + /// methods prior to PEP393. Only used for PY27. + /// + private const string PyUnicodeEntryPoint = "PyUnicodeUCS2_"; +#else +#error You must define either UCS2 or UCS4! #endif -#if (PYTHON23) - internal const string dllBase = "python23"; -#endif -#if (PYTHON24) - internal const string dllBase = "python24"; -#endif -#if (PYTHON25) - internal const string dllBase = "python25"; -#endif -#if (PYTHON26) - internal const string dllBase = "python26"; -#endif -#if (PYTHON27) - internal const string dllBase = "python27"; -#endif -#if (MONO_LINUX || MONO_OSX) -#if (PYTHON32) - internal const string dllBase = "python3.2"; -#endif -#if (PYTHON33) - internal const string dllBase = "python3.3"; -#endif -#if (PYTHON34) - internal const string dllBase = "python3.4"; -#endif -#if (PYTHON35) - internal const string dllBase = "python3.5"; -#endif -#if (PYTHON36) - internal const string dllBase = "python3.6"; -#endif + // C# compiler copies constants to the assemblies that references this library. + // We needs to replace all public constants to static readonly fields to allow + // binary substitution of different Python.Runtime.dll builds in a target application. + + public static string pyversion => _pyversion; + public static string pyver => _pyver; + +#if PYTHON27 + internal const string _pyversion = "2.7"; + internal const string _pyver = "27"; +#elif PYTHON33 + internal const string _pyversion = "3.3"; + internal const string _pyver = "33"; +#elif PYTHON34 + internal const string _pyversion = "3.4"; + internal const string _pyver = "34"; +#elif PYTHON35 + internal const string _pyversion = "3.5"; + internal const string _pyver = "35"; +#elif PYTHON36 + internal const string _pyversion = "3.6"; + internal const string _pyver = "36"; +#elif PYTHON37 // TODO: Add `interop37.cs` after PY37 is released + internal const string _pyversion = "3.7"; + internal const string _pyver = "37"; #else -#if (PYTHON32) - internal const string dllBase = "python32"; -#endif -#if (PYTHON33) - internal const string dllBase = "python33"; -#endif -#if (PYTHON34) - internal const string dllBase = "python34"; -#endif -#if (PYTHON35) - internal const string dllBase = "python35"; -#endif -#if (PYTHON36) - internal const string dllBase = "python36"; +#error You must define one of PYTHON33 to PYTHON37 or PYTHON27 #endif + +#if MONO_LINUX || MONO_OSX // Linux/macOS use dotted version string + internal const string dllBase = "python" + _pyversion; +#else // Windows + internal const string dllBase = "python" + _pyver; #endif -#if (PYTHON_WITH_PYDEBUG) +#if PYTHON_WITH_PYDEBUG internal const string dllWithPyDebug = "d"; #else internal const string dllWithPyDebug = ""; #endif -#if (PYTHON_WITH_PYMALLOC) +#if PYTHON_WITH_PYMALLOC internal const string dllWithPyMalloc = "m"; #else internal const string dllWithPyMalloc = ""; #endif -#if (PYTHON_WITH_WIDE_UNICODE) - internal const string dllWithWideUnicode = "u"; -#else - internal const string dllWithWideUnicode = ""; -#endif -#if (PYTHON_WITHOUT_ENABLE_SHARED) - public const string dll = "__Internal"; + // C# compiler copies constants to the assemblies that references this library. + // We needs to replace all public constants to static readonly fields to allow + // binary substitution of different Python.Runtime.dll builds in a target application. + + public static readonly string PythonDLL = _PythonDll; + +#if PYTHON_WITHOUT_ENABLE_SHARED && !NETSTANDARD + internal const string _PythonDll = "__Internal"; #else - public const string dll = dllBase + dllWithPyDebug + dllWithPyMalloc + dllWithWideUnicode; + internal const string _PythonDll = dllBase + dllWithPyDebug + dllWithPyMalloc; #endif + public static readonly int pyversionnumber = Convert.ToInt32(_pyver); + // set to true when python is finalizing - internal static Object IsFinalizingLock = new Object(); - internal static bool IsFinalizing = false; + internal static object IsFinalizingLock = new object(); + internal static bool IsFinalizing; + + internal static bool Is32Bit = IntPtr.Size == 4; - internal static bool is32bit; + // .NET core: System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + internal static bool IsWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; + + internal static bool IsPython2 = pyversionnumber < 30; + internal static bool IsPython3 = pyversionnumber >= 30; /// - /// Intitialize the runtime... + /// Encoding to use to convert Unicode to/from Managed to Native + /// + internal static readonly Encoding PyEncoding = _UCS == 2 ? Encoding.Unicode : Encoding.UTF32; + + /// + /// Initialize the runtime... /// internal static void Initialize() { - is32bit = IntPtr.Size == 4; - - if (0 == Runtime.Py_IsInitialized()) + if (Py_IsInitialized() == 0) { - Runtime.Py_Initialize(); + Py_Initialize(); } - if (0 == Runtime.PyEval_ThreadsInitialized()) + if (PyEval_ThreadsInitialized() == 0) { - Runtime.PyEval_InitThreads(); + PyEval_InitThreads(); } -#if PYTHON3 - IntPtr op = Runtime.PyImport_ImportModule("builtins"); - IntPtr dict = Runtime.PyObject_GetAttrString(op, "__dict__"); -#elif PYTHON2 - IntPtr dict = Runtime.PyImport_GetModuleDict(); - IntPtr op = Runtime.PyDict_GetItemString(dict, "__builtin__"); -#endif - PyNotImplemented = Runtime.PyObject_GetAttrString(op, "NotImplemented"); - PyBaseObjectType = Runtime.PyObject_GetAttrString(op, "object"); + IntPtr op; + IntPtr dict; + if (IsPython3) + { + op = PyImport_ImportModule("builtins"); + dict = PyObject_GetAttrString(op, "__dict__"); + } + else // Python2 + { + dict = PyImport_GetModuleDict(); + op = PyDict_GetItemString(dict, "__builtin__"); + } + PyNotImplemented = PyObject_GetAttrString(op, "NotImplemented"); + PyBaseObjectType = PyObject_GetAttrString(op, "object"); - PyModuleType = Runtime.PyObject_Type(op); - PyNone = Runtime.PyObject_GetAttrString(op, "None"); - PyTrue = Runtime.PyObject_GetAttrString(op, "True"); - PyFalse = Runtime.PyObject_GetAttrString(op, "False"); + PyModuleType = PyObject_Type(op); + PyNone = PyObject_GetAttrString(op, "None"); + PyTrue = PyObject_GetAttrString(op, "True"); + PyFalse = PyObject_GetAttrString(op, "False"); - PyBoolType = Runtime.PyObject_Type(PyTrue); - PyNoneType = Runtime.PyObject_Type(PyNone); - PyTypeType = Runtime.PyObject_Type(PyNoneType); + PyBoolType = PyObject_Type(PyTrue); + PyNoneType = PyObject_Type(PyNone); + PyTypeType = PyObject_Type(PyNoneType); - op = Runtime.PyObject_GetAttrString(dict, "keys"); - PyMethodType = Runtime.PyObject_Type(op); - Runtime.XDecref(op); + op = PyObject_GetAttrString(dict, "keys"); + PyMethodType = PyObject_Type(op); + XDecref(op); // For some arcane reason, builtins.__dict__.__setitem__ is *not* // a wrapper_descriptor, even though dict.__setitem__ is. // // object.__init__ seems safe, though. - op = Runtime.PyObject_GetAttrString(PyBaseObjectType, "__init__"); - PyWrapperDescriptorType = Runtime.PyObject_Type(op); - Runtime.XDecref(op); + op = PyObject_GetAttrString(PyBaseObjectType, "__init__"); + PyWrapperDescriptorType = PyObject_Type(op); + XDecref(op); #if PYTHON3 - Runtime.XDecref(dict); + XDecref(dict); #endif - op = Runtime.PyString_FromString("string"); - PyStringType = Runtime.PyObject_Type(op); - Runtime.XDecref(op); + op = PyString_FromString("string"); + PyStringType = PyObject_Type(op); + XDecref(op); - op = Runtime.PyUnicode_FromString("unicode"); - PyUnicodeType = Runtime.PyObject_Type(op); - Runtime.XDecref(op); + op = PyUnicode_FromString("unicode"); + PyUnicodeType = PyObject_Type(op); + XDecref(op); #if PYTHON3 - op = Runtime.PyBytes_FromString("bytes"); - PyBytesType = Runtime.PyObject_Type(op); - Runtime.XDecref(op); + op = PyBytes_FromString("bytes"); + PyBytesType = PyObject_Type(op); + XDecref(op); #endif - op = Runtime.PyTuple_New(0); - PyTupleType = Runtime.PyObject_Type(op); - Runtime.XDecref(op); + op = PyTuple_New(0); + PyTupleType = PyObject_Type(op); + XDecref(op); - op = Runtime.PyList_New(0); - PyListType = Runtime.PyObject_Type(op); - Runtime.XDecref(op); + op = PyList_New(0); + PyListType = PyObject_Type(op); + XDecref(op); - op = Runtime.PyDict_New(); - PyDictType = Runtime.PyObject_Type(op); - Runtime.XDecref(op); + op = PyDict_New(); + PyDictType = PyObject_Type(op); + XDecref(op); - op = Runtime.PyInt_FromInt32(0); - PyIntType = Runtime.PyObject_Type(op); - Runtime.XDecref(op); + op = PyInt_FromInt32(0); + PyIntType = PyObject_Type(op); + XDecref(op); - op = Runtime.PyLong_FromLong(0); - PyLongType = Runtime.PyObject_Type(op); - Runtime.XDecref(op); + op = PyLong_FromLong(0); + PyLongType = PyObject_Type(op); + XDecref(op); - op = Runtime.PyFloat_FromDouble(0); - PyFloatType = Runtime.PyObject_Type(op); - Runtime.XDecref(op); + op = PyFloat_FromDouble(0); + PyFloatType = PyObject_Type(op); + XDecref(op); #if PYTHON3 - PyClassType = IntPtr.Zero; - PyInstanceType = IntPtr.Zero; + PyClassType = IntPtr.Zero; + PyInstanceType = IntPtr.Zero; #elif PYTHON2 - IntPtr s = Runtime.PyString_FromString("_temp"); - IntPtr d = Runtime.PyDict_New(); + IntPtr s = PyString_FromString("_temp"); + IntPtr d = PyDict_New(); - IntPtr c = Runtime.PyClass_New(IntPtr.Zero, d, s); - PyClassType = Runtime.PyObject_Type(c); + IntPtr c = PyClass_New(IntPtr.Zero, d, s); + PyClassType = PyObject_Type(c); - IntPtr i = Runtime.PyInstance_New(c, IntPtr.Zero, IntPtr.Zero); - PyInstanceType = Runtime.PyObject_Type(i); + IntPtr i = PyInstance_New(c, IntPtr.Zero, IntPtr.Zero); + PyInstanceType = PyObject_Type(i); - Runtime.XDecref(s); - Runtime.XDecref(i); - Runtime.XDecref(c); - Runtime.XDecref(d); + XDecref(s); + XDecref(i); + XDecref(c); + XDecref(d); #endif Error = new IntPtr(-1); -#if PYTHON3 - IntPtr dll = IntPtr.Zero; - if ("__Internal" != Runtime.dll) { - NativeMethods.LoadLibrary(Runtime.dll); - } - _PyObject_NextNotImplemented = NativeMethods.GetProcAddress(dll, "_PyObject_NextNotImplemented"); + IntPtr dllLocal = IntPtr.Zero; + + if (_PythonDll != "__Internal") + { + dllLocal = NativeMethods.LoadLibrary(_PythonDll); + } + _PyObject_NextNotImplemented = NativeMethods.GetProcAddress(dllLocal, "_PyObject_NextNotImplemented"); + #if !(MONO_LINUX || MONO_OSX) - if (IntPtr.Zero != dll) { - NativeMethods.FreeLibrary(dll); - } -#endif + if (dllLocal != IntPtr.Zero) + { + NativeMethods.FreeLibrary(dllLocal); + } #endif // Initialize modules that depend on the runtime class. @@ -357,10 +344,10 @@ internal static void Initialize() // Need to add the runtime directory to sys.path so that we // can find built-in assemblies like System.Data, et. al. string rtdir = RuntimeEnvironment.GetRuntimeDirectory(); - IntPtr path = Runtime.PySys_GetObject("path"); - IntPtr item = Runtime.PyString_FromString(rtdir); - Runtime.PyList_Append(path, item); - Runtime.XDecref(item); + IntPtr path = PySys_GetObject("path"); + IntPtr item = PyString_FromString(rtdir); + PyList_Append(path, item); + XDecref(item); AssemblyManager.UpdatePath(); } @@ -372,7 +359,7 @@ internal static void Shutdown() Py_Finalize(); } - // called *without* the GIL aquired by clr._AtExit + // called *without* the GIL acquired by clr._AtExit internal static int AtExit() { lock (IsFinalizingLock) @@ -408,8 +395,8 @@ internal static int AtExit() #if PYTHON3 internal static IntPtr PyBytesType; - internal static IntPtr _PyObject_NextNotImplemented; #endif + internal static IntPtr _PyObject_NextNotImplemented; internal static IntPtr PyNotImplemented; internal const int Py_LT = 0; @@ -424,48 +411,40 @@ internal static int AtExit() internal static IntPtr PyNone; internal static IntPtr Error; - internal static IntPtr GetBoundArgTuple(IntPtr obj, IntPtr args) + /// + /// Check if any Python Exceptions occurred. + /// If any exist throw new PythonException. + /// + /// + /// Can be used instead of `obj == IntPtr.Zero` for example. + /// + internal static void CheckExceptionOccurred() { - if (Runtime.PyObject_TYPE(args) != Runtime.PyTupleType) + if (PyErr_Occurred() != 0) { - Exceptions.SetError(Exceptions.TypeError, "tuple expected"); - return IntPtr.Zero; + throw new PythonException(); } - int size = Runtime.PyTuple_Size(args); - IntPtr items = Runtime.PyTuple_New(size + 1); - Runtime.PyTuple_SetItem(items, 0, obj); - Runtime.XIncref(obj); - - for (int i = 0; i < size; i++) - { - IntPtr item = Runtime.PyTuple_GetItem(args, i); - Runtime.XIncref(item); - Runtime.PyTuple_SetItem(items, i + 1, item); - } - - return items; } - internal static IntPtr ExtendTuple(IntPtr t, params IntPtr[] args) { - int size = Runtime.PyTuple_Size(t); + int size = PyTuple_Size(t); int add = args.Length; IntPtr item; - IntPtr items = Runtime.PyTuple_New(size + add); - for (int i = 0; i < size; i++) + IntPtr items = PyTuple_New(size + add); + for (var i = 0; i < size; i++) { - item = Runtime.PyTuple_GetItem(t, i); - Runtime.XIncref(item); - Runtime.PyTuple_SetItem(items, i, item); + item = PyTuple_GetItem(t, i); + XIncref(item); + PyTuple_SetItem(items, i, item); } - for (int n = 0; n < add; n++) + for (var n = 0; n < add; n++) { item = args[n]; - Runtime.XIncref(item); - Runtime.PyTuple_SetItem(items, size + n, item); + XIncref(item); + PyTuple_SetItem(items, size + n, item); } return items; @@ -482,26 +461,26 @@ internal static Type[] PythonArgsToTypeArray(IntPtr arg, bool mangleObjects) // tuple of (managed or unmanaged) type objects, return a Type[] // containing the CLR Type objects that map to those types. IntPtr args = arg; - bool free = false; + var free = false; - if (!Runtime.PyTuple_Check(arg)) + if (!PyTuple_Check(arg)) { - args = Runtime.PyTuple_New(1); - Runtime.XIncref(arg); - Runtime.PyTuple_SetItem(args, 0, arg); + args = PyTuple_New(1); + XIncref(arg); + PyTuple_SetItem(args, 0, arg); free = true; } - int n = Runtime.PyTuple_Size(args); - Type[] types = new Type[n]; + int n = PyTuple_Size(args); + var types = new Type[n]; Type t = null; - for (int i = 0; i < n; i++) + for (var i = 0; i < n; i++) { - IntPtr op = Runtime.PyTuple_GetItem(args, i); - if (mangleObjects && (!Runtime.PyType_Check(op))) + IntPtr op = PyTuple_GetItem(args, i); + if (mangleObjects && (!PyType_Check(op))) { - op = Runtime.PyObject_TYPE(op); + op = PyObject_TYPE(op); } ManagedType mt = ManagedType.GetManagedObject(op); @@ -531,28 +510,26 @@ internal static Type[] PythonArgsToTypeArray(IntPtr arg, bool mangleObjects) } if (free) { - Runtime.XDecref(args); + XDecref(args); } return types; } - //=================================================================== - // Managed exports of the Python C API. Where appropriate, we do - // some optimization to avoid managed <--> unmanaged transitions - // (mostly for heavily used methods). - //=================================================================== - - internal unsafe static void XIncref(IntPtr op) + /// + /// Managed exports of the Python C API. Where appropriate, we do + /// some optimization to avoid managed <--> unmanaged transitions + /// (mostly for heavily used methods). + /// + internal static unsafe void XIncref(IntPtr op) { -#if (Py_DEBUG) - // according to Python doc, Py_IncRef() is Py_XINCREF() - Py_IncRef(op); - return; +#if PYTHON_WITH_PYDEBUG || NETSTANDARD + Py_IncRef(op); + return; #else - void* p = (void*)op; + var p = (void*)op; if ((void*)0 != p) { - if (is32bit) + if (Is32Bit) { (*(int*)p)++; } @@ -566,16 +543,14 @@ internal unsafe static void XIncref(IntPtr op) internal static unsafe void XDecref(IntPtr op) { -#if (Py_DEBUG) - // Py_DecRef calls Python's Py_DECREF - // according to Python doc, Py_DecRef() is Py_XDECREF() - Py_DecRef(op); - return; +#if PYTHON_WITH_PYDEBUG || NETSTANDARD + Py_DecRef(op); + return; #else - void* p = (void*)op; + var p = (void*)op; if ((void*)0 != p) { - if (is32bit) + if (Is32Bit) { --(*(int*)p); } @@ -586,11 +561,11 @@ internal static unsafe void XDecref(IntPtr op) if ((*(int*)p) == 0) { // PyObject_HEAD: struct _typeobject *ob_type - void* t = is32bit + void* t = Is32Bit ? (void*)(*((uint*)p + 1)) : (void*)(*((ulong*)p + 1)); // PyTypeObject: destructor tp_dealloc - void* f = is32bit + void* f = Is32Bit ? (void*)(*((uint*)t + 6)) : (void*)(*((ulong*)t + 6)); if ((void*)0 == f) @@ -598,364 +573,226 @@ internal static unsafe void XDecref(IntPtr op) return; } NativeCall.Impl.Void_Call_1(new IntPtr(f), op); - return; } } #endif } - internal unsafe static long Refcount(IntPtr op) + internal static unsafe long Refcount(IntPtr op) { - void* p = (void*)op; - if ((void*)0 != p) + var p = (void*)op; + if ((void*)0 == p) { - if (is32bit) - { - return (*(int*)p); - } - else - { - return (*(long*)p); - } + return 0; } - return 0; + return Is32Bit ? (*(int*)p) : (*(long*)p); } -#if (Py_DEBUG) - // Py_IncRef and Py_DecRef are taking care of the extra payload - // in Py_DEBUG builds of Python like _Py_RefTotal - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - private unsafe static extern void - Py_IncRef(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - private unsafe static extern void - Py_DecRef(IntPtr ob); -#endif + /// + /// Export of Macro Py_XIncRef. Use XIncref instead. + /// Limit this function usage for Testing and Py_Debug builds + /// + /// PyObject Ptr + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void Py_IncRef(IntPtr ob); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - Py_Initialize(); + /// + /// Export of Macro Py_XDecRef. Use XDecref instead. + /// Limit this function usage for Testing and Py_Debug builds + /// + /// PyObject Ptr + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void Py_DecRef(IntPtr ob); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - Py_IsInitialized(); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void Py_Initialize(); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - Py_Finalize(); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int Py_IsInitialized(); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - Py_NewInterpreter(); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void Py_Finalize(); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - Py_EndInterpreter(IntPtr threadState); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr Py_NewInterpreter(); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyThreadState_New(IntPtr istate); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void Py_EndInterpreter(IntPtr threadState); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyThreadState_Get(); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyThreadState_New(IntPtr istate); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyThread_get_key_value(IntPtr key); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyThreadState_Get(); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyThread_get_thread_ident(); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyThread_get_key_value(IntPtr key); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyThread_set_key_value(IntPtr key, IntPtr value); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyThread_get_thread_ident(); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyThreadState_Swap(IntPtr key); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyThread_set_key_value(IntPtr key, IntPtr value); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyThreadState_Swap(IntPtr key); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyGILState_Ensure(); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyGILState_Ensure(); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyGILState_Release(IntPtr gs); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyGILState_Release(IntPtr gs); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyGILState_GetThisThreadState(); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyGILState_GetThisThreadState(); #if PYTHON3 - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - public unsafe static extern int - Py_Main(int argc, [MarshalAsAttribute(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPWStr)] string[] argv); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + public static extern int Py_Main( + int argc, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StrArrayMarshaler))] string[] argv + ); #elif PYTHON2 - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - public unsafe static extern int - Py_Main(int argc, string[] argv); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + public static extern int Py_Main(int argc, string[] argv); #endif - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyEval_InitThreads(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyEval_ThreadsInitialized(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyEval_AcquireLock(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyEval_ReleaseLock(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyEval_AcquireThread(IntPtr tstate); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyEval_ReleaseThread(IntPtr tstate); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyEval_SaveThread(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyEval_RestoreThread(IntPtr tstate); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyEval_GetBuiltins(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyEval_GetGlobals(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyEval_GetLocals(); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyEval_InitThreads(); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyEval_ThreadsInitialized(); -#if PYTHON3 - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - [return: MarshalAs(UnmanagedType.LPWStr)] - internal unsafe static extern string - Py_GetProgramName(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - Py_SetProgramName([MarshalAsAttribute(UnmanagedType.LPWStr)]string name); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - [return: MarshalAs(UnmanagedType.LPWStr)] - internal unsafe static extern string - Py_GetPythonHome(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - Py_SetPythonHome([MarshalAsAttribute(UnmanagedType.LPWStr)]string home); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - [return: MarshalAs(UnmanagedType.LPWStr)] - internal unsafe static extern string - Py_GetPath(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - Py_SetPath([MarshalAsAttribute(UnmanagedType.LPWStr)]string home); -#elif PYTHON2 - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern string - Py_GetProgramName(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - Py_SetProgramName(string name); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern string - Py_GetPythonHome(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - Py_SetPythonHome(string home); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern string - Py_GetPath(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - Py_SetPath(string home); -#endif + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyEval_AcquireLock(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyEval_ReleaseLock(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyEval_AcquireThread(IntPtr tstate); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern string - Py_GetVersion(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern string - Py_GetPlatform(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern string - Py_GetCopyright(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern string - Py_GetCompiler(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern string - Py_GetBuildInfo(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyRun_SimpleString(string code); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyRun_String(string code, IntPtr st, IntPtr globals, IntPtr locals); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - Py_CompileString(string code, string file, IntPtr tok); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyImport_ExecCodeModule(string name, IntPtr code); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyCFunction_NewEx(IntPtr ml, IntPtr self, IntPtr mod); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyCFunction_Call(IntPtr func, IntPtr args, IntPtr kw); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyClass_New(IntPtr bases, IntPtr dict, IntPtr name); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyInstance_New(IntPtr cls, IntPtr args, IntPtr kw); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyInstance_NewRaw(IntPtr cls, IntPtr dict); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyMethod_New(IntPtr func, IntPtr self, IntPtr cls); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyEval_ReleaseThread(IntPtr tstate); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyEval_SaveThread(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyEval_RestoreThread(IntPtr tstate); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyEval_GetBuiltins(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyEval_GetGlobals(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyEval_GetLocals(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr Py_GetProgramName(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void Py_SetProgramName(IntPtr name); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr Py_GetPythonHome(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void Py_SetPythonHome(IntPtr home); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr Py_GetPath(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void Py_SetPath(IntPtr home); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr Py_GetVersion(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr Py_GetPlatform(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr Py_GetCopyright(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr Py_GetCompiler(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr Py_GetBuildInfo(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyRun_SimpleString(string code); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyRun_String(string code, IntPtr st, IntPtr globals, IntPtr locals); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyEval_EvalCode(IntPtr co, IntPtr globals, IntPtr locals); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr Py_CompileString(string code, string file, IntPtr tok); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyImport_ExecCodeModule(string name, IntPtr code); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyCFunction_NewEx(IntPtr ml, IntPtr self, IntPtr mod); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyCFunction_Call(IntPtr func, IntPtr args, IntPtr kw); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyClass_New(IntPtr bases, IntPtr dict, IntPtr name); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyInstance_New(IntPtr cls, IntPtr args, IntPtr kw); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyInstance_NewRaw(IntPtr cls, IntPtr dict); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyMethod_New(IntPtr func, IntPtr self, IntPtr cls); //==================================================================== // Python abstract object API //==================================================================== - // A macro-like method to get the type of a Python object. This is - // designed to be lean and mean in IL & avoid managed <-> unmanaged - // transitions. Note that this does not incref the type object. - - internal unsafe static IntPtr - PyObject_TYPE(IntPtr op) + /// + /// A macro-like method to get the type of a Python object. This is + /// designed to be lean and mean in IL & avoid managed <-> unmanaged + /// transitions. Note that this does not incref the type object. + /// + internal static unsafe IntPtr PyObject_TYPE(IntPtr op) { - void* p = (void*)op; + var p = (void*)op; if ((void*)0 == p) { return IntPtr.Zero; } -#if (Py_DEBUG) - int n = 3; +#if PYTHON_WITH_PYDEBUG + var n = 3; #else - int n = 1; + var n = 1; #endif - if (is32bit) - { - return new IntPtr((void*)(*((uint*)p + n))); - } - else - { - return new IntPtr((void*)(*((ulong*)p + n))); - } + return Is32Bit + ? new IntPtr((void*)(*((uint*)p + n))) + : new IntPtr((void*)(*((ulong*)p + n))); } - // Managed version of the standard Python C API PyObject_Type call. - // This version avoids a managed <-> unmanaged transition. This one - // does incref the returned type object. - - internal unsafe static IntPtr - PyObject_Type(IntPtr op) + /// + /// Managed version of the standard Python C API PyObject_Type call. + /// This version avoids a managed <-> unmanaged transition. + /// This one does incref the returned type object. + /// + internal static IntPtr PyObject_Type(IntPtr op) { IntPtr tp = PyObject_TYPE(op); - Runtime.XIncref(tp); + XIncref(tp); return tp; } @@ -966,165 +803,128 @@ internal static string PyObject_GetTypeName(IntPtr op) return Marshal.PtrToStringAnsi(ppName); } - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyObject_HasAttrString(IntPtr pointer, string name); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_GetAttrString(IntPtr pointer, string name); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyObject_SetAttrString(IntPtr pointer, string name, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyObject_HasAttr(IntPtr pointer, IntPtr name); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_GetAttr(IntPtr pointer, IntPtr name); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyObject_SetAttr(IntPtr pointer, IntPtr name, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_GetItem(IntPtr pointer, IntPtr key); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyObject_SetItem(IntPtr pointer, IntPtr key, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyObject_DelItem(IntPtr pointer, IntPtr key); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_GetIter(IntPtr op); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_Call(IntPtr pointer, IntPtr args, IntPtr kw); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_CallObject(IntPtr pointer, IntPtr args); + /// + /// Test whether the Python object is an iterable. + /// + internal static bool PyObject_IsIterable(IntPtr pointer) + { + var ob_type = Marshal.ReadIntPtr(pointer, ObjectOffset.ob_type); +#if PYTHON2 + long tp_flags = Util.ReadCLong(ob_type, TypeOffset.tp_flags); + if ((tp_flags & TypeFlags.HaveIter) == 0) + return false; +#endif + IntPtr tp_iter = Marshal.ReadIntPtr(ob_type, TypeOffset.tp_iter); + return tp_iter != IntPtr.Zero; + } + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyObject_HasAttrString(IntPtr pointer, string name); -#if PYTHON3 - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyObject_RichCompareBool(IntPtr value1, IntPtr value2, int opid); - - internal static int PyObject_Compare(IntPtr value1, IntPtr value2) { - int res; - res = PyObject_RichCompareBool(value1, value2, Py_LT); - if (-1 == res) - return -1; - else if (1 == res) - return -1; + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyObject_GetAttrString(IntPtr pointer, string name); - res = PyObject_RichCompareBool(value1, value2, Py_EQ); - if (-1 == res) - return -1; - else if (1 == res) - return 0; + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyObject_SetAttrString(IntPtr pointer, string name, IntPtr value); - res = PyObject_RichCompareBool(value1, value2, Py_GT); - if (-1 == res) - return -1; - else if (1 == res) - return 1; + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyObject_HasAttr(IntPtr pointer, IntPtr name); - Exceptions.SetError(Exceptions.SystemError, "Error comparing objects"); - return -1; - } + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyObject_GetAttr(IntPtr pointer, IntPtr name); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyObject_SetAttr(IntPtr pointer, IntPtr name, IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyObject_GetItem(IntPtr pointer, IntPtr key); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyObject_SetItem(IntPtr pointer, IntPtr key, IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyObject_DelItem(IntPtr pointer, IntPtr key); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyObject_GetIter(IntPtr op); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyObject_Call(IntPtr pointer, IntPtr args, IntPtr kw); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyObject_CallObject(IntPtr pointer, IntPtr args); + +#if PYTHON3 + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyObject_RichCompareBool(IntPtr value1, IntPtr value2, int opid); + + internal static int PyObject_Compare(IntPtr value1, IntPtr value2) + { + int res; + res = PyObject_RichCompareBool(value1, value2, Py_LT); + if (-1 == res) + return -1; + else if (1 == res) + return -1; + + res = PyObject_RichCompareBool(value1, value2, Py_EQ); + if (-1 == res) + return -1; + else if (1 == res) + return 0; + + res = PyObject_RichCompareBool(value1, value2, Py_GT); + if (-1 == res) + return -1; + else if (1 == res) + return 1; + + Exceptions.SetError(Exceptions.SystemError, "Error comparing objects"); + return -1; + } #elif PYTHON2 - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyObject_Compare(IntPtr value1, IntPtr value2); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyObject_Compare(IntPtr value1, IntPtr value2); #endif + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyObject_IsInstance(IntPtr ob, IntPtr type); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyObject_IsInstance(IntPtr ob, IntPtr type); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyObject_IsSubclass(IntPtr ob, IntPtr type); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyObject_IsSubclass(IntPtr ob, IntPtr type); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyCallable_Check(IntPtr pointer); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyCallable_Check(IntPtr pointer); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyObject_IsTrue(IntPtr pointer); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyObject_IsTrue(IntPtr pointer); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyObject_Not(IntPtr pointer); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyObject_Not(IntPtr pointer); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyObject_Size(IntPtr pointer); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyObject_Size(IntPtr pointer); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_Hash(IntPtr op); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyObject_Hash(IntPtr op); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_Repr(IntPtr pointer); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyObject_Repr(IntPtr pointer); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_Str(IntPtr pointer); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyObject_Str(IntPtr pointer); #if PYTHON3 - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint="PyObject_Str", - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_Unicode(IntPtr pointer); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "PyObject_Str")] + internal static extern IntPtr PyObject_Unicode(IntPtr pointer); #elif PYTHON2 - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_Unicode(IntPtr pointer); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyObject_Unicode(IntPtr pointer); #endif - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_Dir(IntPtr pointer); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyObject_Dir(IntPtr pointer); //==================================================================== @@ -1132,384 +932,248 @@ internal unsafe static extern IntPtr //==================================================================== #if PYTHON3 - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint = "PyNumber_Long", - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Int(IntPtr ob); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "PyNumber_Long")] + internal static extern IntPtr PyNumber_Int(IntPtr ob); #elif PYTHON2 - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Int(IntPtr ob); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Int(IntPtr ob); #endif - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Long(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Float(IntPtr ob); - + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Long(IntPtr ob); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern bool - PyNumber_Check(IntPtr ob); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Float(IntPtr ob); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool PyNumber_Check(IntPtr ob); internal static bool PyInt_Check(IntPtr ob) { - return PyObject_TypeCheck(ob, Runtime.PyIntType); + return PyObject_TypeCheck(ob, PyIntType); } internal static bool PyBool_Check(IntPtr ob) { - return PyObject_TypeCheck(ob, Runtime.PyBoolType); + return PyObject_TypeCheck(ob, PyBoolType); } internal static IntPtr PyInt_FromInt32(int value) { - IntPtr v = new IntPtr(value); + var v = new IntPtr(value); return PyInt_FromLong(v); } internal static IntPtr PyInt_FromInt64(long value) { - IntPtr v = new IntPtr(value); + var v = new IntPtr(value); return PyInt_FromLong(v); } #if PYTHON3 - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyLong_FromLong", - ExactSpelling = true, CharSet = CharSet.Ansi)] - private unsafe static extern IntPtr - PyInt_FromLong(IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint = "PyLong_AsLong", - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyInt_AsLong(IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint = "PyLong_FromString", - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyInt_FromString(string value, IntPtr end, int radix); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint = "PyLong_GetMax", - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyInt_GetMax(); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "PyLong_FromLong")] + private static extern IntPtr PyInt_FromLong(IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "PyLong_AsLong")] + internal static extern int PyInt_AsLong(IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "PyLong_FromString")] + internal static extern IntPtr PyInt_FromString(string value, IntPtr end, int radix); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "PyLong_GetMax")] + internal static extern int PyInt_GetMax(); #elif PYTHON2 + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr PyInt_FromLong(IntPtr value); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - private unsafe static extern IntPtr - PyInt_FromLong(IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyInt_AsLong(IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyInt_FromString(string value, IntPtr end, int radix); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyInt_GetMax(); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyInt_AsLong(IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyInt_FromString(string value, IntPtr end, int radix); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyInt_GetMax(); #endif internal static bool PyLong_Check(IntPtr ob) { - return PyObject_TYPE(ob) == Runtime.PyLongType; + return PyObject_TYPE(ob) == PyLongType; } - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyLong_FromLong(long value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyLong_FromUnsignedLong(uint value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyLong_FromDouble(double value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyLong_FromLongLong(long value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyLong_FromUnsignedLongLong(ulong value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyLong_FromString(string value, IntPtr end, int radix); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyLong_AsLong(IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern uint - PyLong_AsUnsignedLong(IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern long - PyLong_AsLongLong(IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern ulong - PyLong_AsUnsignedLongLong(IntPtr value); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyLong_FromLong(long value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyLong_FromUnsignedLong(uint value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyLong_FromDouble(double value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyLong_FromLongLong(long value); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyLong_FromUnsignedLongLong(ulong value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyLong_FromString(string value, IntPtr end, int radix); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyLong_AsLong(IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint PyLong_AsUnsignedLong(IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern long PyLong_AsLongLong(IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern ulong PyLong_AsUnsignedLongLong(IntPtr value); internal static bool PyFloat_Check(IntPtr ob) { - return PyObject_TYPE(ob) == Runtime.PyFloatType; + return PyObject_TYPE(ob) == PyFloatType; } - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyFloat_FromDouble(double value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyFloat_FromString(IntPtr value, IntPtr junk); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern double - PyFloat_AsDouble(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Add(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Subtract(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Multiply(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Divide(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_And(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Xor(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Or(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Lshift(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Rshift(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Power(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Remainder(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_InPlaceAdd(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_InPlaceSubtract(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_InPlaceMultiply(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_InPlaceDivide(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_InPlaceAnd(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_InPlaceXor(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_InPlaceOr(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_InPlaceLshift(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_InPlaceRshift(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_InPlacePower(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_InPlaceRemainder(IntPtr o1, IntPtr o2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Negative(IntPtr o1); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Positive(IntPtr o1); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Invert(IntPtr o1); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyFloat_FromDouble(double value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyFloat_FromString(IntPtr value, IntPtr junk); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern double PyFloat_AsDouble(IntPtr ob); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Add(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Subtract(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Multiply(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Divide(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_And(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Xor(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Or(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Lshift(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Rshift(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Power(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Remainder(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_InPlaceAdd(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_InPlaceSubtract(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_InPlaceMultiply(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_InPlaceDivide(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_InPlaceAnd(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_InPlaceXor(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_InPlaceOr(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_InPlaceLshift(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_InPlaceRshift(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_InPlacePower(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_InPlaceRemainder(IntPtr o1, IntPtr o2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Negative(IntPtr o1); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Positive(IntPtr o1); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyNumber_Invert(IntPtr o1); + //==================================================================== // Python sequence API //==================================================================== - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern bool - PySequence_Check(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PySequence_GetItem(IntPtr pointer, int index); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PySequence_SetItem(IntPtr pointer, int index, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PySequence_DelItem(IntPtr pointer, int index); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PySequence_GetSlice(IntPtr pointer, int i1, int i2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PySequence_SetSlice(IntPtr pointer, int i1, int i2, IntPtr v); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PySequence_DelSlice(IntPtr pointer, int i1, int i2); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PySequence_Size(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PySequence_Contains(IntPtr pointer, IntPtr item); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PySequence_Concat(IntPtr pointer, IntPtr other); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PySequence_Repeat(IntPtr pointer, int count); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PySequence_Index(IntPtr pointer, IntPtr item); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PySequence_Count(IntPtr pointer, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PySequence_Tuple(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PySequence_List(IntPtr pointer); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool PySequence_Check(IntPtr pointer); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PySequence_GetItem(IntPtr pointer, int index); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PySequence_SetItem(IntPtr pointer, int index, IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PySequence_DelItem(IntPtr pointer, int index); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PySequence_GetSlice(IntPtr pointer, int i1, int i2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PySequence_SetSlice(IntPtr pointer, int i1, int i2, IntPtr v); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PySequence_DelSlice(IntPtr pointer, int i1, int i2); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PySequence_Size(IntPtr pointer); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PySequence_Contains(IntPtr pointer, IntPtr item); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PySequence_Concat(IntPtr pointer, IntPtr other); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PySequence_Repeat(IntPtr pointer, int count); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PySequence_Index(IntPtr pointer, IntPtr item); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PySequence_Count(IntPtr pointer, IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PySequence_Tuple(IntPtr pointer); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PySequence_List(IntPtr pointer); //==================================================================== @@ -1524,7 +1188,7 @@ internal static bool IsStringType(IntPtr op) internal static bool PyString_Check(IntPtr ob) { - return PyObject_TYPE(ob) == Runtime.PyStringType; + return PyObject_TYPE(ob) == PyStringType; } internal static IntPtr PyString_FromString(string value) @@ -1533,324 +1197,141 @@ internal static IntPtr PyString_FromString(string value) } #if PYTHON3 - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyBytes_FromString(string op); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyBytes_Size(IntPtr op); - - internal static IntPtr PyBytes_AS_STRING(IntPtr ob) { - return ob + BytesOffset.ob_sval; - } + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyBytes_FromString(string op); - internal static IntPtr PyString_FromStringAndSize(string value, int length) - { - // copy the string into an unmanaged UTF-8 buffer - int len = Encoding.UTF8.GetByteCount(value); - byte[] buffer = new byte[len + 1]; - Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, 0); - IntPtr nativeUtf8 = Marshal.AllocHGlobal(buffer.Length); - try { - Marshal.Copy(buffer, 0, nativeUtf8, buffer.Length); - return PyUnicode_FromStringAndSize(nativeUtf8, length); - } - finally { - Marshal.FreeHGlobal(nativeUtf8); - } - } + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyBytes_Size(IntPtr op); -#if (PYTHON33 || PYTHON34 || PYTHON35 || PYTHON36) - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromStringAndSize(IntPtr value, int size); -#elif (UCS2) - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyUnicodeUCS2_FromStringAndSize", - ExactSpelling = true, CharSet = CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromStringAndSize(IntPtr value, int size); -#else - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyUnicodeUCS4_FromStringAndSize", - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyUnicode_FromStringAndSize(IntPtr value, int size); -#endif + internal static IntPtr PyBytes_AS_STRING(IntPtr ob) + { + return ob + BytesOffset.ob_sval; + } -#else // Python2x + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "PyUnicode_FromStringAndSize")] + internal static extern IntPtr PyString_FromStringAndSize( + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string value, + int size + ); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyString_FromStringAndSize(string value, int size); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyUnicode_FromStringAndSize(IntPtr value, int size); +#elif PYTHON2 + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyString_FromStringAndSize(string value, int size); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyString_AsString", - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyString_AS_STRING(IntPtr op); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyString_AsString(IntPtr op); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyString_Size(IntPtr pointer); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyString_Size(IntPtr pointer); #endif internal static bool PyUnicode_Check(IntPtr ob) { - return PyObject_TYPE(ob) == Runtime.PyUnicodeType; + return PyObject_TYPE(ob) == PyUnicodeType; } -#if (UCS2) -#if (PYTHON33 || PYTHON34 || PYTHON35 || PYTHON36) - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromObject(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromEncodedObject(IntPtr ob, IntPtr enc, IntPtr err); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint="PyUnicode_FromKindAndData", - ExactSpelling=true, - CharSet=CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromKindAndString(int kind, string s, int size); - - internal static IntPtr PyUnicode_FromUnicode(string s, int size) { - return PyUnicode_FromKindAndString(2, s, size); - } - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Unicode)] - internal unsafe static extern int - PyUnicode_GetSize(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Unicode)] - internal unsafe static extern char * - PyUnicode_AsUnicode(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyUnicode_AsUnicode", - ExactSpelling = true, CharSet = CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_AS_UNICODE(IntPtr op); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromOrdinal(int c); - -#else - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint="PyUnicodeUCS2_FromObject", - ExactSpelling=true, CharSet=CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromObject(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint="PyUnicodeUCS2_FromEncodedObject", - ExactSpelling=true, CharSet=CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromEncodedObject(IntPtr ob, IntPtr enc, IntPtr err); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint="PyUnicodeUCS2_FromUnicode", - ExactSpelling=true, CharSet=CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromUnicode(string s, int size); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint="PyUnicodeUCS2_GetSize", - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyUnicode_GetSize(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint="PyUnicodeUCS2_AsUnicode", - ExactSpelling=true)] - internal unsafe static extern char * - PyUnicode_AsUnicode(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint="PyUnicodeUCS2_AsUnicode", - ExactSpelling=true, CharSet=CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_AS_UNICODE(IntPtr op); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint="PyUnicodeUCS2_FromOrdinal", - ExactSpelling=true, CharSet=CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromOrdinal(int c); -#endif +#if PYTHON3 + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyUnicode_FromObject(IntPtr ob); - internal static IntPtr PyUnicode_FromString(string s) - { - return PyUnicode_FromUnicode(s, (s.Length)); - } + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyUnicode_FromEncodedObject(IntPtr ob, IntPtr enc, IntPtr err); - internal unsafe static string GetManagedString(IntPtr op) - { - IntPtr type = PyObject_TYPE(op); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyUnicode_FromKindAndData( + int kind, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UcsMarshaler))] string s, + int size + ); -// Python 3 strings are all unicode -#if PYTHON2 - if (type == Runtime.PyStringType) + internal static IntPtr PyUnicode_FromUnicode(string s, int size) { - return Marshal.PtrToStringAnsi( - PyString_AS_STRING(op), - Runtime.PyString_Size(op) - ); + return PyUnicode_FromKindAndData(_UCS, s, size); } -#endif - if (type == Runtime.PyUnicodeType) - { - char* p = Runtime.PyUnicode_AsUnicode(op); - int size = Runtime.PyUnicode_GetSize(op); - return new String(p, 0, size); - } + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyUnicode_GetSize(IntPtr ob); - return null; - } + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyUnicode_AsUnicode(IntPtr ob); -#endif -#if (UCS4) -#if (PYTHON33 || PYTHON34 || PYTHON35 || PYTHON36) - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromObject(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromEncodedObject(IntPtr ob, IntPtr enc, IntPtr err); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyUnicode_FromKindAndData", - ExactSpelling = true)] - internal unsafe static extern IntPtr - PyUnicode_FromKindAndString(int kind, - [MarshalAs (UnmanagedType.CustomMarshaler, - MarshalTypeRef=typeof(Utf32Marshaler))] string s, - int size); - - internal static IntPtr PyUnicode_FromUnicode(string s, int size) { - return PyUnicode_FromKindAndString(4, s, size); - } - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyUnicode_GetSize(IntPtr ob); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyUnicode_FromOrdinal(int c); +#elif PYTHON2 + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = PyUnicodeEntryPoint + "FromObject")] + internal static extern IntPtr PyUnicode_FromObject(IntPtr ob); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true)] - internal unsafe static extern IntPtr - PyUnicode_AsUnicode(IntPtr ob); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = PyUnicodeEntryPoint + "FromEncodedObject")] + internal static extern IntPtr PyUnicode_FromEncodedObject(IntPtr ob, IntPtr enc, IntPtr err); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyUnicode_AsUnicode", - ExactSpelling = true, CharSet = CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_AS_UNICODE(IntPtr op); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = PyUnicodeEntryPoint + "FromUnicode")] + internal static extern IntPtr PyUnicode_FromUnicode( + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UcsMarshaler))] string s, + int size + ); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromOrdinal(int c); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = PyUnicodeEntryPoint + "GetSize")] + internal static extern int PyUnicode_GetSize(IntPtr ob); -#else - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyUnicodeUCS4_FromObject", - ExactSpelling = true, CharSet = CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromObject(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyUnicodeUCS4_FromEncodedObject", - ExactSpelling = true, CharSet = CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromEncodedObject(IntPtr ob, IntPtr enc, IntPtr err); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyUnicodeUCS4_FromUnicode", - ExactSpelling = true)] - internal unsafe static extern IntPtr - PyUnicode_FromUnicode( - [MarshalAs(UnmanagedType.CustomMarshaler, - MarshalTypeRef = typeof(Utf32Marshaler))] string s, int size); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyUnicodeUCS4_GetSize", - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyUnicode_GetSize(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyUnicodeUCS4_AsUnicode", - ExactSpelling = true)] - internal unsafe static extern IntPtr - PyUnicode_AsUnicode(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyUnicodeUCS4_AsUnicode", - ExactSpelling = true, CharSet = CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_AS_UNICODE(IntPtr op); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyUnicodeUCS4_FromOrdinal", - ExactSpelling = true, CharSet = CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromOrdinal(int c); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = PyUnicodeEntryPoint + "AsUnicode")] + internal static extern IntPtr PyUnicode_AsUnicode(IntPtr ob); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = PyUnicodeEntryPoint + "FromOrdinal")] + internal static extern IntPtr PyUnicode_FromOrdinal(int c); #endif internal static IntPtr PyUnicode_FromString(string s) { - return PyUnicode_FromUnicode(s, (s.Length)); + return PyUnicode_FromUnicode(s, s.Length); } - internal unsafe static string GetManagedString(IntPtr op) + /// + /// Function to access the internal PyUnicode/PyString object and + /// convert it to a managed string with the correct encoding. + /// + /// + /// We can't easily do this through through the CustomMarshaler's on + /// the returns because will have access to the IntPtr but not size. + /// + /// For PyUnicodeType, we can't convert with Marshal.PtrToStringUni + /// since it only works for UCS2. + /// + /// PyStringType or PyUnicodeType object to convert + /// Managed String + internal static string GetManagedString(IntPtr op) { IntPtr type = PyObject_TYPE(op); -// Python 3 strings are all unicode -#if PYTHON2 - if (type == Runtime.PyStringType) +#if PYTHON2 // Python 3 strings are all Unicode + if (type == PyStringType) { - return Marshal.PtrToStringAnsi( - PyString_AS_STRING(op), - Runtime.PyString_Size(op) - ); + return Marshal.PtrToStringAnsi(PyString_AsString(op), PyString_Size(op)); } #endif - if (type == Runtime.PyUnicodeType) + if (type == PyUnicodeType) { - IntPtr p = Runtime.PyUnicode_AsUnicode(op); - int length = Runtime.PyUnicode_GetSize(op); - int size = length*4; - byte[] buffer = new byte[size]; + IntPtr p = PyUnicode_AsUnicode(op); + int length = PyUnicode_GetSize(op); + + int size = length * _UCS; + var buffer = new byte[size]; Marshal.Copy(p, buffer, 0, size); - return Encoding.UTF32.GetString(buffer, 0, size); + return PyEncoding.GetString(buffer, 0, size); } return null; } -#endif + //==================================================================== // Python dictionary API @@ -1858,88 +1339,56 @@ internal unsafe static string GetManagedString(IntPtr op) internal static bool PyDict_Check(IntPtr ob) { - return PyObject_TYPE(ob) == Runtime.PyDictType; + return PyObject_TYPE(ob) == PyDictType; } - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDict_New(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDictProxy_New(IntPtr dict); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDict_GetItem(IntPtr pointer, IntPtr key); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDict_GetItemString(IntPtr pointer, string key); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyDict_SetItem(IntPtr pointer, IntPtr key, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyDict_SetItemString(IntPtr pointer, string key, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyDict_DelItem(IntPtr pointer, IntPtr key); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyDict_DelItemString(IntPtr pointer, string key); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyMapping_HasKey(IntPtr pointer, IntPtr key); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDict_Keys(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDict_Values(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDict_Items(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDict_Copy(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyDict_Update(IntPtr pointer, IntPtr other); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyDict_Clear(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyDict_Size(IntPtr pointer); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyDict_New(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyDictProxy_New(IntPtr dict); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyDict_GetItem(IntPtr pointer, IntPtr key); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyDict_GetItemString(IntPtr pointer, string key); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyDict_SetItem(IntPtr pointer, IntPtr key, IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyDict_SetItemString(IntPtr pointer, string key, IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyDict_DelItem(IntPtr pointer, IntPtr key); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyDict_DelItemString(IntPtr pointer, string key); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyMapping_HasKey(IntPtr pointer, IntPtr key); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyDict_Keys(IntPtr pointer); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyDict_Values(IntPtr pointer); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyDict_Items(IntPtr pointer); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyDict_Copy(IntPtr pointer); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyDict_Update(IntPtr pointer, IntPtr other); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyDict_Clear(IntPtr pointer); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyDict_Size(IntPtr pointer); //==================================================================== @@ -1948,63 +1397,41 @@ internal unsafe static extern int internal static bool PyList_Check(IntPtr ob) { - return PyObject_TYPE(ob) == Runtime.PyListType; + return PyObject_TYPE(ob) == PyListType; } - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyList_New(int size); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyList_AsTuple(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyList_GetItem(IntPtr pointer, int index); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyList_SetItem(IntPtr pointer, int index, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyList_Insert(IntPtr pointer, int index, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyList_Append(IntPtr pointer, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyList_Reverse(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyList_Sort(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyList_GetSlice(IntPtr pointer, int start, int end); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyList_SetSlice(IntPtr pointer, int start, int end, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyList_Size(IntPtr pointer); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyList_New(int size); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyList_AsTuple(IntPtr pointer); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyList_GetItem(IntPtr pointer, int index); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyList_SetItem(IntPtr pointer, int index, IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyList_Insert(IntPtr pointer, int index, IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyList_Append(IntPtr pointer, IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyList_Reverse(IntPtr pointer); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyList_Sort(IntPtr pointer); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyList_GetSlice(IntPtr pointer, int start, int end); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyList_SetSlice(IntPtr pointer, int start, int end, IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyList_Size(IntPtr pointer); //==================================================================== @@ -2013,130 +1440,102 @@ internal unsafe static extern int internal static bool PyTuple_Check(IntPtr ob) { - return PyObject_TYPE(ob) == Runtime.PyTupleType; + return PyObject_TYPE(ob) == PyTupleType; } - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyTuple_New(int size); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyTuple_New(int size); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyTuple_GetItem(IntPtr pointer, int index); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyTuple_GetItem(IntPtr pointer, int index); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyTuple_SetItem(IntPtr pointer, int index, IntPtr value); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyTuple_SetItem(IntPtr pointer, int index, IntPtr value); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyTuple_GetSlice(IntPtr pointer, int start, int end); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyTuple_GetSlice(IntPtr pointer, int start, int end); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyTuple_Size(IntPtr pointer); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyTuple_Size(IntPtr pointer); //==================================================================== // Python iterator API //==================================================================== + internal static bool PyIter_Check(IntPtr pointer) + { + var ob_type = Marshal.ReadIntPtr(pointer, ObjectOffset.ob_type); #if PYTHON2 - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern bool - PyIter_Check(IntPtr pointer); -#elif PYTHON3 - internal static bool - PyIter_Check(IntPtr pointer) - { - IntPtr ob_type = (IntPtr)Marshal.PtrToStructure(pointer + ObjectOffset.ob_type, typeof(IntPtr)); - IntPtr tp_iternext = ob_type + TypeOffset.tp_iternext; - return tp_iternext != null && tp_iternext != _PyObject_NextNotImplemented; - } + long tp_flags = Util.ReadCLong(ob_type, TypeOffset.tp_flags); + if ((tp_flags & TypeFlags.HaveIter) == 0) + return false; #endif + IntPtr tp_iternext = Marshal.ReadIntPtr(ob_type, TypeOffset.tp_iternext); + return tp_iternext != IntPtr.Zero && tp_iternext != _PyObject_NextNotImplemented; + } + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyIter_Next(IntPtr pointer); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyIter_Next(IntPtr pointer); //==================================================================== // Python module API //==================================================================== - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyModule_New(string name); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyModule_New(string name); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern string - PyModule_GetName(IntPtr module); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern string PyModule_GetName(IntPtr module); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyModule_GetDict(IntPtr module); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyModule_GetDict(IntPtr module); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern string - PyModule_GetFilename(IntPtr module); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern string PyModule_GetFilename(IntPtr module); #if PYTHON3 - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyModule_Create2(IntPtr module, int apiver); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyModule_Create2(IntPtr module, int apiver); #endif - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyImport_Import(IntPtr name); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyImport_ImportModule(string name); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyImport_Import(IntPtr name); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyImport_ReloadModule(IntPtr module); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyImport_ImportModule(string name); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyImport_AddModule(string name); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyImport_ReloadModule(IntPtr module); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyImport_GetModuleDict(); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyImport_AddModule(string name); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyImport_GetModuleDict(); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PySys_SetArgv(int argc, IntPtr argv); +#if PYTHON3 + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PySys_SetArgvEx( + int argc, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StrArrayMarshaler))] string[] argv, + int updatepath + ); +#elif PYTHON2 + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PySys_SetArgvEx( + int argc, + string[] argv, + int updatepath + ); +#endif - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PySys_GetObject(string name); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PySys_GetObject(string name); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PySys_SetObject(string name, IntPtr ob); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PySys_SetObject(string name, IntPtr ob); //==================================================================== @@ -2145,18 +1544,14 @@ internal unsafe static extern int internal static bool PyType_Check(IntPtr ob) { - return PyObject_TypeCheck(ob, Runtime.PyTypeType); + return PyObject_TypeCheck(ob, PyTypeType); } - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyType_Modified(IntPtr type); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyType_Modified(IntPtr type); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern bool - PyType_IsSubtype(IntPtr t1, IntPtr t2); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool PyType_IsSubtype(IntPtr t1, IntPtr t2); internal static bool PyObject_TypeCheck(IntPtr ob, IntPtr tp) { @@ -2164,159 +1559,103 @@ internal static bool PyObject_TypeCheck(IntPtr ob, IntPtr tp) return (t == tp) || PyType_IsSubtype(t, tp); } - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyType_GenericNew(IntPtr type, IntPtr args, IntPtr kw); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyType_GenericAlloc(IntPtr type, int n); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyType_Ready(IntPtr type); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - _PyType_Lookup(IntPtr type, IntPtr name); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_GenericGetAttr(IntPtr obj, IntPtr name); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyObject_GenericSetAttr(IntPtr obj, IntPtr name, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - _PyObject_GetDictPtr(IntPtr obj); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_GC_New(IntPtr tp); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyObject_GC_Del(IntPtr tp); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyObject_GC_Track(IntPtr tp); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyObject_GC_UnTrack(IntPtr tp); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyType_GenericNew(IntPtr type, IntPtr args, IntPtr kw); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyType_GenericAlloc(IntPtr type, int n); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyType_Ready(IntPtr type); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr _PyType_Lookup(IntPtr type, IntPtr name); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyObject_GenericGetAttr(IntPtr obj, IntPtr name); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyObject_GenericSetAttr(IntPtr obj, IntPtr name, IntPtr value); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr _PyObject_GetDictPtr(IntPtr obj); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyObject_GC_New(IntPtr tp); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyObject_GC_Del(IntPtr tp); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyObject_GC_Track(IntPtr tp); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyObject_GC_UnTrack(IntPtr tp); //==================================================================== // Python memory API //==================================================================== - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyMem_Malloc(int size); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyMem_Malloc(int size); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyMem_Realloc(IntPtr ptr, int size); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyMem_Realloc(IntPtr ptr, int size); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyMem_Free(IntPtr ptr); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyMem_Free(IntPtr ptr); //==================================================================== // Python exception API //==================================================================== - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyErr_SetString(IntPtr ob, string message); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyErr_SetObject(IntPtr ob, IntPtr message); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyErr_SetFromErrno(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyErr_SetNone(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyErr_ExceptionMatches(IntPtr exception); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyErr_GivenExceptionMatches(IntPtr ob, IntPtr val); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyErr_NormalizeException(IntPtr ob, IntPtr val, IntPtr tb); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern int - PyErr_Occurred(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyErr_Fetch(ref IntPtr ob, ref IntPtr val, ref IntPtr tb); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyErr_Restore(IntPtr ob, IntPtr val, IntPtr tb); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyErr_Clear(); - - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern void - PyErr_Print(); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyErr_SetString(IntPtr ob, string message); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyErr_SetObject(IntPtr ob, IntPtr message); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyErr_SetFromErrno(IntPtr ob); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyErr_SetNone(IntPtr ob); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyErr_ExceptionMatches(IntPtr exception); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyErr_GivenExceptionMatches(IntPtr ob, IntPtr val); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyErr_NormalizeException(IntPtr ob, IntPtr val, IntPtr tb); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int PyErr_Occurred(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyErr_Fetch(ref IntPtr ob, ref IntPtr val, ref IntPtr tb); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyErr_Restore(IntPtr ob, IntPtr val, IntPtr tb); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyErr_Clear(); + + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern void PyErr_Print(); //==================================================================== // Miscellaneous //==================================================================== - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyMethod_Self(IntPtr ob); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyMethod_Self(IntPtr ob); - [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, - ExactSpelling = true, CharSet = CharSet.Ansi)] - internal unsafe static extern IntPtr - PyMethod_Function(IntPtr ob); + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr PyMethod_Function(IntPtr ob); } } diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs index 40e60336d..6570ee083 100644 --- a/src/runtime/typemanager.cs +++ b/src/runtime/typemanager.cs @@ -1,22 +1,19 @@ -using System; -using System.Runtime.InteropServices; -using System.Reflection.Emit; -using System.Collections.Generic; +using System; using System.Collections; +using System.Collections.Generic; using System.Reflection; -using System.Threading; +using System.Runtime.InteropServices; namespace Python.Runtime { - //======================================================================= - // The TypeManager class is responsible for building binary-compatible - // Python type objects that are implemented in managed code. - //======================================================================= - + /// + /// The TypeManager class is responsible for building binary-compatible + /// Python type objects that are implemented in managed code. + /// internal class TypeManager { - static BindingFlags tbFlags; - static Dictionary cache; + private static BindingFlags tbFlags; + private static Dictionary cache; static TypeManager() { @@ -25,18 +22,17 @@ static TypeManager() } - //==================================================================== - // Given a managed Type derived from ExtensionType, get the handle to - // a Python type object that delegates its implementation to the Type - // object. These Python type instances are used to implement internal - // descriptor and utility types like ModuleObject, PropertyObject, etc. - //==================================================================== - + /// + /// Given a managed Type derived from ExtensionType, get the handle to + /// a Python type object that delegates its implementation to the Type + /// object. These Python type instances are used to implement internal + /// descriptor and utility types like ModuleObject, PropertyObject, etc. + /// internal static IntPtr GetTypeHandle(Type type) { // Note that these types are cached with a refcount of 1, so they // effectively exist until the CPython runtime is finalized. - IntPtr handle = IntPtr.Zero; + IntPtr handle; cache.TryGetValue(type, out handle); if (handle != IntPtr.Zero) { @@ -48,15 +44,14 @@ internal static IntPtr GetTypeHandle(Type type) } - //==================================================================== - // Get the handle of a Python type that reflects the given CLR type. - // The given ManagedType instance is a managed object that implements - // the appropriate semantics in Python for the reflected managed type. - //==================================================================== - + /// + /// Get the handle of a Python type that reflects the given CLR type. + /// The given ManagedType instance is a managed object that implements + /// the appropriate semantics in Python for the reflected managed type. + /// internal static IntPtr GetTypeHandle(ManagedType obj, Type type) { - IntPtr handle = IntPtr.Zero; + IntPtr handle; cache.TryGetValue(type, out handle); if (handle != IntPtr.Zero) { @@ -68,15 +63,14 @@ internal static IntPtr GetTypeHandle(ManagedType obj, Type type) } - //==================================================================== - // The following CreateType implementations do the necessary work to - // create Python types to represent managed extension types, reflected - // types, subclasses of reflected types and the managed metatype. The - // dance is slightly different for each kind of type due to different - // behavior needed and the desire to have the existing Python runtime - // do as much of the allocation and initialization work as possible. - //==================================================================== - + /// + /// The following CreateType implementations do the necessary work to + /// create Python types to represent managed extension types, reflected + /// types, subclasses of reflected types and the managed metatype. The + /// dance is slightly different for each kind of type due to different + /// behavior needed and the desire to have the existing Python runtime + /// do as much of the allocation and initialization work as possible. + /// internal static IntPtr CreateType(Type impl) { IntPtr type = AllocateTypeObject(impl.Name); @@ -85,14 +79,14 @@ internal static IntPtr CreateType(Type impl) // Set tp_basicsize to the size of our managed instance objects. Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size); - IntPtr offset = (IntPtr)ObjectOffset.DictOffset(type); + var offset = (IntPtr)ObjectOffset.DictOffset(type); Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset); InitializeSlots(type, impl); int flags = TypeFlags.Default | TypeFlags.Managed | TypeFlags.HeapType | TypeFlags.HaveGC; - Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); + Util.WriteCLong(type, TypeOffset.tp_flags, flags); Runtime.PyType_Ready(type); @@ -128,13 +122,13 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType) // XXX Hack, use a different base class for System.Exception // Python 2.5+ allows new style class exceptions but they *must* // subclass BaseException (or better Exception). - if (typeof(System.Exception).IsAssignableFrom(clrType)) + if (typeof(Exception).IsAssignableFrom(clrType)) { ob_size = ObjectOffset.Size(Exceptions.Exception); tp_dictoffset = ObjectOffset.DictOffset(Exceptions.Exception); } - if (clrType == typeof(System.Exception)) + if (clrType == typeof(Exception)) { base_ = Exceptions.Exception; } @@ -166,7 +160,7 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType) flags |= TypeFlags.HeapType; flags |= TypeFlags.BaseType; flags |= TypeFlags.HaveGC; - Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); + Util.WriteCLong(type, TypeOffset.tp_flags, flags); // Leverage followup initialization from the Python runtime. Note // that the type of the new type must PyType_Type at the time we @@ -175,7 +169,7 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType) Runtime.PyType_Ready(type); IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); - string mn = clrType.Namespace != null ? clrType.Namespace : ""; + string mn = clrType.Namespace ?? ""; IntPtr mod = Runtime.PyString_FromString(mn); Runtime.PyDict_SetItemString(dict, "__module__", mod); @@ -204,37 +198,45 @@ internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr object assembly = null; object namespaceStr = null; - List disposeList = new List(); + var disposeList = new List(); try { - PyObject assemblyKey = new PyObject(Converter.ToPython("__assembly__", typeof(String))); + var assemblyKey = new PyObject(Converter.ToPython("__assembly__", typeof(string))); disposeList.Add(assemblyKey); if (0 != Runtime.PyMapping_HasKey(py_dict, assemblyKey.Handle)) { - PyObject pyAssembly = new PyObject(Runtime.PyDict_GetItem(py_dict, assemblyKey.Handle)); + var pyAssembly = new PyObject(Runtime.PyDict_GetItem(py_dict, assemblyKey.Handle)); + Runtime.XIncref(pyAssembly.Handle); disposeList.Add(pyAssembly); - if (!Converter.ToManagedValue(pyAssembly.Handle, typeof(String), out assembly, false)) + if (!Converter.ToManagedValue(pyAssembly.Handle, typeof(string), out assembly, false)) + { throw new InvalidCastException("Couldn't convert __assembly__ value to string"); + } } - PyObject namespaceKey = new PyObject(Converter.ToPythonImplicit("__namespace__")); + var namespaceKey = new PyObject(Converter.ToPythonImplicit("__namespace__")); disposeList.Add(namespaceKey); if (0 != Runtime.PyMapping_HasKey(py_dict, namespaceKey.Handle)) { - PyObject pyNamespace = new PyObject(Runtime.PyDict_GetItem(py_dict, namespaceKey.Handle)); + var pyNamespace = new PyObject(Runtime.PyDict_GetItem(py_dict, namespaceKey.Handle)); + Runtime.XIncref(pyNamespace.Handle); disposeList.Add(pyNamespace); - if (!Converter.ToManagedValue(pyNamespace.Handle, typeof(String), out namespaceStr, false)) + if (!Converter.ToManagedValue(pyNamespace.Handle, typeof(string), out namespaceStr, false)) + { throw new InvalidCastException("Couldn't convert __namespace__ value to string"); + } } } finally { foreach (PyObject o in disposeList) + { o.Dispose(); + } } // create the new managed type subclassing the base managed type - ClassBase baseClass = ManagedType.GetManagedObject(py_base_type) as ClassBase; + var baseClass = ManagedType.GetManagedObject(py_base_type) as ClassBase; if (null == baseClass) { return Exceptions.RaiseTypeError("invalid base class, expected CLR class type"); @@ -268,10 +270,10 @@ internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr internal static IntPtr WriteMethodDef(IntPtr mdef, IntPtr name, IntPtr func, int flags, IntPtr doc) { Marshal.WriteIntPtr(mdef, name); - Marshal.WriteIntPtr(mdef, (1*IntPtr.Size), func); - Marshal.WriteInt32(mdef, (2*IntPtr.Size), flags); - Marshal.WriteIntPtr(mdef, (3*IntPtr.Size), doc); - return mdef + 4*IntPtr.Size; + Marshal.WriteIntPtr(mdef, 1 * IntPtr.Size, func); + Marshal.WriteInt32(mdef, 2 * IntPtr.Size, flags); + Marshal.WriteIntPtr(mdef, 3 * IntPtr.Size, doc); + return mdef + 4 * IntPtr.Size; } internal static IntPtr WriteMethodDef(IntPtr mdef, string name, IntPtr func, int flags = 0x0001, @@ -321,24 +323,25 @@ internal static IntPtr CreateMetaType(Type impl) flags |= TypeFlags.Managed; flags |= TypeFlags.HeapType; flags |= TypeFlags.HaveGC; - Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); + Util.WriteCLong(type, TypeOffset.tp_flags, flags); // We need space for 3 PyMethodDef structs, each of them // 4 int-ptrs in size. - IntPtr mdef = Runtime.PyMem_Malloc(3*(4*IntPtr.Size)); + IntPtr mdef = Runtime.PyMem_Malloc(3 * 4 * IntPtr.Size); IntPtr mdefStart = mdef; mdef = WriteMethodDef( mdef, "__instancecheck__", Interop.GetThunk(typeof(MetaType).GetMethod("__instancecheck__"), "BinaryFunc") - ); + ); mdef = WriteMethodDef( mdef, "__subclasscheck__", Interop.GetThunk(typeof(MetaType).GetMethod("__subclasscheck__"), "BinaryFunc") - ); + ); + // FIXME: mdef is not used mdef = WriteMethodDefSentinel(mdef); Marshal.WriteIntPtr(type, TypeOffset.tp_methods, mdefStart); @@ -355,8 +358,7 @@ internal static IntPtr CreateMetaType(Type impl) } - internal static IntPtr BasicSubType(string name, IntPtr base_, - Type impl) + internal static IntPtr BasicSubType(string name, IntPtr base_, Type impl) { // Utility to create a subtype of a std Python type, but with // a managed type able to override implementation @@ -378,7 +380,7 @@ internal static IntPtr BasicSubType(string name, IntPtr base_, flags |= TypeFlags.Managed; flags |= TypeFlags.HeapType; flags |= TypeFlags.HaveGC; - Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); + Util.WriteCLong(type, TypeOffset.tp_flags, flags); CopySlot(base_, type, TypeOffset.tp_traverse); CopySlot(base_, type, TypeOffset.tp_clear); @@ -396,10 +398,9 @@ internal static IntPtr BasicSubType(string name, IntPtr base_, } - //==================================================================== - // Utility method to allocate a type object & do basic initialization. - //==================================================================== - + /// + /// Utility method to allocate a type object & do basic initialization. + /// internal static IntPtr AllocateTypeObject(string name) { IntPtr type = Runtime.PyType_GenericAlloc(Runtime.PyTypeType, 0); @@ -408,15 +409,15 @@ internal static IntPtr AllocateTypeObject(string name) // the Python version of the type name - otherwise we'd have to // allocate the tp_name and would have no way to free it. #if PYTHON3 - // For python3 we leak two objects. One for the ascii representation - // required for tp_name, and another for the unicode representation - // for ht_name. + // For python3 we leak two objects. One for the ASCII representation + // required for tp_name, and another for the Unicode representation + // for ht_name. IntPtr temp = Runtime.PyBytes_FromString(name); IntPtr raw = Runtime.PyBytes_AS_STRING(temp); temp = Runtime.PyUnicode_FromString(name); #elif PYTHON2 IntPtr temp = Runtime.PyString_FromString(name); - IntPtr raw = Runtime.PyString_AS_STRING(temp); + IntPtr raw = Runtime.PyString_AsString(temp); #endif Marshal.WriteIntPtr(type, TypeOffset.tp_name, raw); Marshal.WriteIntPtr(type, TypeOffset.name, temp); @@ -438,40 +439,36 @@ internal static IntPtr AllocateTypeObject(string name) #if PYTHON3 temp = new IntPtr(ptr + TypeOffset.bf_getbuffer); - Marshal.WriteIntPtr(type, TypeOffset.tp_as_buffer, temp); #elif PYTHON2 temp = new IntPtr(ptr + TypeOffset.bf_getreadbuffer); - Marshal.WriteIntPtr(type, TypeOffset.tp_as_buffer, temp); #endif - + Marshal.WriteIntPtr(type, TypeOffset.tp_as_buffer, temp); return type; } - //==================================================================== - // Given a newly allocated Python type object and a managed Type that - // provides the implementation for the type, connect the type slots of - // the Python object to the managed methods of the implementing Type. - //==================================================================== - + /// + /// Given a newly allocated Python type object and a managed Type that + /// provides the implementation for the type, connect the type slots of + /// the Python object to the managed methods of the implementing Type. + /// internal static void InitializeSlots(IntPtr type, Type impl) { - Hashtable seen = new Hashtable(8); + var seen = new Hashtable(8); Type offsetType = typeof(TypeOffset); while (impl != null) { MethodInfo[] methods = impl.GetMethods(tbFlags); - for (int i = 0; i < methods.Length; i++) + foreach (MethodInfo method in methods) { - MethodInfo method = methods[i]; string name = method.Name; if (!(name.StartsWith("tp_") || name.StartsWith("nb_") || name.StartsWith("sq_") || name.StartsWith("mp_") || name.StartsWith("bf_") - )) + )) { continue; } @@ -482,7 +479,7 @@ internal static void InitializeSlots(IntPtr type, Type impl) } FieldInfo fi = offsetType.GetField(name); - int offset = (int)fi.GetValue(offsetType); + var offset = (int)fi.GetValue(offsetType); IntPtr slot = Interop.GetThunk(method); Marshal.WriteIntPtr(type, offset, slot); @@ -495,33 +492,31 @@ internal static void InitializeSlots(IntPtr type, Type impl) } - //==================================================================== - // Given a newly allocated Python type object and a managed Type that - // implements it, initialize any methods defined by the Type that need - // to appear in the Python type __dict__ (based on custom attribute). - //==================================================================== - + /// + /// Given a newly allocated Python type object and a managed Type that + /// implements it, initialize any methods defined by the Type that need + /// to appear in the Python type __dict__ (based on custom attribute). + /// private static void InitMethods(IntPtr pytype, Type type) { IntPtr dict = Marshal.ReadIntPtr(pytype, TypeOffset.tp_dict); Type marker = typeof(PythonMethodAttribute); BindingFlags flags = BindingFlags.Public | BindingFlags.Static; - HashSet addedMethods = new HashSet(); + var addedMethods = new HashSet(); while (type != null) { MethodInfo[] methods = type.GetMethods(flags); - for (int i = 0; i < methods.Length; i++) + foreach (MethodInfo method in methods) { - MethodInfo method = methods[i]; if (!addedMethods.Contains(method.Name)) { object[] attrs = method.GetCustomAttributes(marker, false); if (attrs.Length > 0) { string method_name = method.Name; - MethodInfo[] mi = new MethodInfo[1]; + var mi = new MethodInfo[1]; mi[0] = method; MethodObject m = new TypeMethod(type, method_name, mi); Runtime.PyDict_SetItemString(dict, method_name, m.pyHandle); @@ -534,10 +529,9 @@ private static void InitMethods(IntPtr pytype, Type type) } - //==================================================================== - // Utility method to copy slots from a given type to another type. - //==================================================================== - + /// + /// Utility method to copy slots from a given type to another type. + /// internal static void CopySlot(IntPtr from, IntPtr to, int offset) { IntPtr fp = Marshal.ReadIntPtr(from, offset); diff --git a/src/runtime/typemethod.cs b/src/runtime/typemethod.cs index 4e46da2da..4da92613c 100644 --- a/src/runtime/typemethod.cs +++ b/src/runtime/typemethod.cs @@ -1,13 +1,11 @@ using System; -using System.Collections; using System.Reflection; namespace Python.Runtime { - //======================================================================== - // Implements a Python type that provides access to CLR object methods. - //======================================================================== - + /// + /// Implements a Python type that provides access to CLR object methods. + /// internal class TypeMethod : MethodObject { public TypeMethod(Type type, string name, MethodInfo[] info) : @@ -22,21 +20,20 @@ public TypeMethod(Type type, string name, MethodInfo[] info, bool allow_threads) public override IntPtr Invoke(IntPtr ob, IntPtr args, IntPtr kw) { - MethodInfo mi = this.info[0]; - Object[] arglist = new Object[3]; + MethodInfo mi = info[0]; + var arglist = new object[3]; arglist[0] = ob; arglist[1] = args; arglist[2] = kw; try { - Object inst = null; + object inst = null; if (ob != IntPtr.Zero) { inst = GetManagedObject(ob); } - return (IntPtr)mi.Invoke(inst, BindingFlags.Default, null, arglist, - null); + return (IntPtr)mi.Invoke(inst, BindingFlags.Default, null, arglist, null); } catch (Exception e) { @@ -45,4 +42,4 @@ public override IntPtr Invoke(IntPtr ob, IntPtr args, IntPtr kw) } } } -} \ No newline at end of file +} diff --git a/src/runtime/x64/clrmodule-platform.il b/src/runtime/x64/clrmodule-platform.il deleted file mode 100644 index bb188df52..000000000 --- a/src/runtime/x64/clrmodule-platform.il +++ /dev/null @@ -1,3 +0,0 @@ - -.vtfixup [1] int64 fromunmanaged at VT_01 -.data VT_01 = int64(0) diff --git a/src/runtime/x86/clrmodule-platform.il b/src/runtime/x86/clrmodule-platform.il deleted file mode 100644 index f4855c5e2..000000000 --- a/src/runtime/x86/clrmodule-platform.il +++ /dev/null @@ -1,3 +0,0 @@ - -.vtfixup [1] int32 fromunmanaged at VT_01 -.data VT_01 = int32(0) diff --git a/src/testing/Python.Test.15.csproj b/src/testing/Python.Test.15.csproj new file mode 100644 index 000000000..da20ed2ef --- /dev/null +++ b/src/testing/Python.Test.15.csproj @@ -0,0 +1,86 @@ + + + + net40;netstandard2.0 + x64;x86 + DebugMono;DebugMonoPY3;ReleaseMono;ReleaseMonoPY3;DebugWin;DebugWinPY3;ReleaseWin;ReleaseWinPY3 + Python.Test + Python.Test + Python.Test + 2.4.0 + bin\ + false + $(OutputPath)\$(AssemblyName).xml + $(OutputPath)\$(TargetFramework)\$(AssemblyName).xml + 1591,0067 + ..\..\ + $(SolutionDir)\bin\ + $(PythonBuildDir)\$(TargetFramework)\ + 6 + false + ..\pythonnet.snk + prompt + $(PYTHONNET_DEFINE_CONSTANTS) + XPLAT + $(DefineConstants);$(CustomDefineConstants);$(BaseDefineConstants); + $(DefineConstants);TRACE;DEBUG + $(NuGetPackageRoot)\microsoft.targetingpack.netframework.v4.5\1.0.1\lib\net45\ + + + x86 + + + x64 + + + + false + full + + + true + pdbonly + + + true + false + full + + + true + true + portable + + + + $(DefineConstants);DEBUG;TRACE + + + $(DefineConstants) + + + + + + + + + + + + + + + + + + + $(TargetPath) + $(TargetDir)$(TargetName).pdb + + + + + + + diff --git a/src/testing/Python.Test.csproj b/src/testing/Python.Test.csproj index 4566aeccf..8a8d9ed2b 100644 --- a/src/testing/Python.Test.csproj +++ b/src/testing/Python.Test.csproj @@ -5,106 +5,69 @@ AnyCPU {6F401A34-273B-450F-9A4C-13550BE0767B} Library - false Python.Test Python.Test - OnBuildSuccess + bin\Python.Test.xml + bin\ v4.0 + 1591,0067 ..\..\ - $(SolutionDir) + $(SolutionDir)\bin\ + 6 + false + ..\pythonnet.snk + prompt - - true - bin\x86\DebugMono\ - DEBUG;TRACE - full + x86 - prompt - true - true - false - + + x64 + + true - bin\x64\DebugMono\ DEBUG;TRACE full - x64 - prompt - true - true - false - - bin\x86\ReleaseMono\ + true pdbonly - x86 - prompt - true - true - false - - bin\x64\ReleaseMono\ + + true + DEBUG;TRACE + full + + true pdbonly - x64 - prompt - true - true - false - + true - bin\x86\DebugWin\ DEBUG;TRACE full - x86 - prompt - true - false - false - - - true - bin\x64\DebugWin\ - DEBUG;TRACE - full - x64 - prompt - true - true - false - - bin\x86\ReleaseWin\ + true pdbonly - x86 - prompt - true - true - false - - bin\x64\ReleaseWin\ + + true + DEBUG;TRACE + full + + true pdbonly - x64 - prompt - true - true - false @@ -131,9 +94,6 @@ - - 3.5 - @@ -142,16 +102,12 @@ - - - - $(SolutionDir) $(TargetPath) $(TargetDir)$(TargetName).pdb - - + + diff --git a/src/testing/arraytest.cs b/src/testing/arraytest.cs index b9891cac8..946684962 100644 --- a/src/testing/arraytest.cs +++ b/src/testing/arraytest.cs @@ -1,12 +1,8 @@ -using System; -using System.Collections; - namespace Python.Test { - //======================================================================== - // Supports units tests for indexer access. - //======================================================================== - + /// + /// Supports units tests for indexer access. + /// public class PublicArrayTest { public int[] items; @@ -318,4 +314,4 @@ public static Spam[][] EchoRangeAA(Spam[][] items) return items; } } -} \ No newline at end of file +} diff --git a/src/testing/callbacktest.cs b/src/testing/callbacktest.cs index f95cbc602..321ecc86f 100644 --- a/src/testing/callbacktest.cs +++ b/src/testing/callbacktest.cs @@ -1,45 +1,44 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using Python.Runtime; namespace Python.Test { - //======================================================================== - // Tests callbacks into python code. - //======================================================================== - + /// + /// Tests callbacks into python code. + /// public class CallbackTest { public string Call_simpleDefaultArg_WithNull(string moduleName) { - using (Runtime.Py.GIL()) + using (Py.GIL()) { - dynamic module = Runtime.Py.Import(moduleName); + dynamic module = Py.Import(moduleName); return module.simpleDefaultArg(null); } } + public string Call_simpleDefaultArg_WithEmptyArgs(string moduleName) { - using (Runtime.Py.GIL()) + using (Py.GIL()) { - dynamic module = Runtime.Py.Import(moduleName); + dynamic module = Py.Import(moduleName); return module.simpleDefaultArg(); } } } - //========================================================================== - // Tests calling from Python into C# and back into Python using a PyObject. - // SelfCallbackTest should be inherited by a Python class. - // Used in test_class.py / testCallback - //========================================================================== + /// + /// Tests calling from Python into C# and back into Python using a PyObject. + /// SelfCallbackTest should be inherited by a Python class. + /// Used in test_class.py / testCallback + /// public class SelfCallbackTest { - public void Callback(Runtime.PyObject self) + public void Callback(PyObject self) { - using (Runtime.Py.GIL()) + using (Py.GIL()) + { ((dynamic)self).PyCallback(self); + } } } } diff --git a/src/testing/classtest.cs b/src/testing/classtest.cs index 5f3b0d7ed..68c0d8c55 100644 --- a/src/testing/classtest.cs +++ b/src/testing/classtest.cs @@ -1,18 +1,16 @@ -using System; using System.Collections; namespace Python.Test { - //======================================================================== - // Supports CLR class unit tests. - //======================================================================== - + /// + /// Supports CLR class unit tests. + /// public class ClassTest { public static ArrayList GetArrayList() { - ArrayList list = new ArrayList(); - for (int i = 0; i < 10; i++) + var list = new ArrayList(); + for (var i = 0; i < 10; i++) { list.Add(i); } @@ -21,7 +19,7 @@ public static ArrayList GetArrayList() public static Hashtable GetHashtable() { - Hashtable dict = new Hashtable(); + var dict = new Hashtable(); dict.Add("one", 1); dict.Add("two", 2); dict.Add("three", 3); @@ -32,7 +30,7 @@ public static Hashtable GetHashtable() public static IEnumerator GetEnumerator() { - string temp = "test string"; + var temp = "test string"; return temp.GetEnumerator(); } } @@ -61,4 +59,4 @@ public ClassCtorTest2(string v) internal class InternalClass { } -} \ No newline at end of file +} diff --git a/src/testing/constructortests.cs b/src/testing/constructortests.cs index cffcee888..8800c94a1 100644 --- a/src/testing/constructortests.cs +++ b/src/testing/constructortests.cs @@ -1,20 +1,18 @@ using System; -using System.Collections; using System.IO; namespace Python.Test { - //======================================================================== - // These classes support the CLR constructor unit tests. - //======================================================================== - + /// + /// These classes support the CLR constructor unit tests. + /// public class EnumConstructorTest { public TypeCode value; public EnumConstructorTest(TypeCode v) { - this.value = v; + value = v; } } @@ -25,7 +23,7 @@ public class FlagsConstructorTest public FlagsConstructorTest(FileAccess v) { - this.value = v; + value = v; } } @@ -36,7 +34,7 @@ public class StructConstructorTest public StructConstructorTest(Guid v) { - this.value = v; + value = v; } } @@ -47,7 +45,7 @@ public class SubclassConstructorTest public SubclassConstructorTest(Exception v) { - this.value = v; + value = v; } } -} \ No newline at end of file +} diff --git a/src/testing/conversiontest.cs b/src/testing/conversiontest.cs index e4d4762e6..36294594c 100644 --- a/src/testing/conversiontest.cs +++ b/src/testing/conversiontest.cs @@ -1,12 +1,8 @@ -using System; - - namespace Python.Test { - //======================================================================== - // Supports units tests for field access. - //======================================================================== - + /// + /// Supports units tests for field access. + /// public class ConversionTest { public ConversionTest() @@ -36,8 +32,14 @@ public ConversionTest() public byte[] ByteArrayField; public sbyte[] SByteArrayField; + + public T? Echo(T? arg) where T: struct { + return arg; + } + } + public interface ISpam { @@ -46,7 +48,7 @@ public interface ISpam public class Spam : ISpam { - string value; + private string value; public Spam(string value) { @@ -58,4 +60,4 @@ public string GetValue() return value; } } -} \ No newline at end of file +} diff --git a/src/testing/delegatetest.cs b/src/testing/delegatetest.cs index d13750c49..e2df9475f 100644 --- a/src/testing/delegatetest.cs +++ b/src/testing/delegatetest.cs @@ -1,11 +1,8 @@ -using System; - namespace Python.Test { - //======================================================================== - // Supports CLR class unit tests. - //======================================================================== - + /// + /// Supports CLR class unit tests. + /// public delegate void PublicDelegate(); internal delegate void InternalDelegate(); @@ -60,4 +57,4 @@ public bool CallBoolDelegate(BoolDelegate d) return d(); } } -} \ No newline at end of file +} diff --git a/src/testing/doctest.cs b/src/testing/doctest.cs index 156248029..98ca05de4 100644 --- a/src/testing/doctest.cs +++ b/src/testing/doctest.cs @@ -2,25 +2,26 @@ namespace Python.Test { - //======================================================================== - // Supports units tests for exposing docstrings from C# to Python - //======================================================================== - - // Classes with a constructor have their docstring set to the ctor signature. - // Test if a class has an explicit doc string it gets set correctly. - [DocStringAttribute("DocWithCtorTest Class")] + /// + /// Supports units tests for exposing docstrings from C# to Python + /// + /// + /// Classes with a constructor have their docstring set to the ctor signature. + /// Test if a class has an explicit doc string it gets set correctly. + /// + [DocString("DocWithCtorTest Class")] public class DocWithCtorTest { public DocWithCtorTest() { } - [DocStringAttribute("DocWithCtorTest TestMethod")] + [DocString("DocWithCtorTest TestMethod")] public void TestMethod() { } - [DocStringAttribute("DocWithCtorTest StaticTestMethod")] + [DocString("DocWithCtorTest StaticTestMethod")] public static void StaticTestMethod() { } @@ -41,17 +42,17 @@ public static void StaticTestMethod(double a, int b) } } - [DocStringAttribute("DocWithoutCtorTest Class")] + [DocString("DocWithoutCtorTest Class")] public class DocWithoutCtorTest { - [DocStringAttribute("DocWithoutCtorTest TestMethod")] + [DocString("DocWithoutCtorTest TestMethod")] public void TestMethod() { } - [DocStringAttribute("DocWithoutCtorTest StaticTestMethod")] + [DocString("DocWithoutCtorTest StaticTestMethod")] public static void StaticTestMethod() { } } -} \ No newline at end of file +} diff --git a/src/testing/enumtest.cs b/src/testing/enumtest.cs index 162771980..de5d8f5ee 100644 --- a/src/testing/enumtest.cs +++ b/src/testing/enumtest.cs @@ -2,10 +2,9 @@ namespace Python.Test { - //======================================================================== - // Supports CLR enum unit tests. - //======================================================================== - + /// + /// Supports CLR enum unit tests. + /// public enum ByteEnum : byte { Zero, @@ -86,7 +85,7 @@ public enum ULongEnum : ulong Five } - [FlagsAttribute] + [Flags] public enum FlagsEnum { Zero, @@ -96,4 +95,4 @@ public enum FlagsEnum Four, Five } -} \ No newline at end of file +} diff --git a/src/testing/eventtest.cs b/src/testing/eventtest.cs index 544e0f259..4c701d488 100644 --- a/src/testing/eventtest.cs +++ b/src/testing/eventtest.cs @@ -2,30 +2,29 @@ namespace Python.Test { - //======================================================================== - // Supports CLR event unit tests. - //======================================================================== - - public delegate void TestEventHandler(object sender, TestEventArgs e); + /// + /// Supports CLR event unit tests. + /// + public delegate void EventHandlerTest(object sender, EventArgsTest e); public class EventTest { - public static event TestEventHandler PublicStaticEvent; + public static event EventHandlerTest PublicStaticEvent; - protected static event TestEventHandler ProtectedStaticEvent; + protected static event EventHandlerTest ProtectedStaticEvent; - internal static event TestEventHandler InternalStaticEvent; + internal static event EventHandlerTest InternalStaticEvent; - private static event TestEventHandler PrivateStaticEvent; + private static event EventHandlerTest PrivateStaticEvent; - public event TestEventHandler PublicEvent; + public event EventHandlerTest PublicEvent; - protected event TestEventHandler ProtectedEvent; + protected event EventHandlerTest ProtectedEvent; - internal event TestEventHandler InternalEvent; + internal event EventHandlerTest InternalEvent; - private event TestEventHandler PrivateEvent; + private event EventHandlerTest PrivateEvent; public static int s_value; @@ -33,7 +32,7 @@ public class EventTest public EventTest() { - this.value = 0; + value = 0; } static EventTest() @@ -42,7 +41,7 @@ static EventTest() } - public void OnPublicEvent(TestEventArgs e) + public void OnPublicEvent(EventArgsTest e) { if (PublicEvent != null) { @@ -51,7 +50,7 @@ public void OnPublicEvent(TestEventArgs e) } - public void OnProtectedEvent(TestEventArgs e) + public void OnProtectedEvent(EventArgsTest e) { if (ProtectedEvent != null) { @@ -60,7 +59,7 @@ public void OnProtectedEvent(TestEventArgs e) } - public static void OnPublicStaticEvent(TestEventArgs e) + public static void OnPublicStaticEvent(EventArgsTest e) { if (PublicStaticEvent != null) { @@ -69,7 +68,7 @@ public static void OnPublicStaticEvent(TestEventArgs e) } - protected static void OnProtectedStaticEvent(TestEventArgs e) + protected static void OnProtectedStaticEvent(EventArgsTest e) { if (ProtectedStaticEvent != null) { @@ -78,12 +77,12 @@ protected static void OnProtectedStaticEvent(TestEventArgs e) } - public void GenericHandler(object sender, TestEventArgs e) + public void GenericHandler(object sender, EventArgsTest e) { - this.value = e.value; + value = e.value; } - public static void StaticHandler(object sender, TestEventArgs e) + public static void StaticHandler(object sender, EventArgsTest e) { s_value = e.value; } @@ -91,8 +90,8 @@ public static void StaticHandler(object sender, TestEventArgs e) public static void ShutUpCompiler() { // Quiet compiler warnings. - EventTest e = new EventTest(); - TestEventHandler f = new TestEventHandler(e.GenericHandler); + var e = new EventTest(); + EventHandlerTest f = e.GenericHandler; ProtectedStaticEvent += f; InternalStaticEvent += f; PrivateStaticEvent += f; @@ -103,13 +102,13 @@ public static void ShutUpCompiler() } - public class TestEventArgs : EventArgs + public class EventArgsTest : EventArgs { public int value; - public TestEventArgs(int v) + public EventArgsTest(int v) { - this.value = v; + value = v; } } -} \ No newline at end of file +} diff --git a/src/testing/exceptiontest.cs b/src/testing/exceptiontest.cs index 414c25d82..e4f683721 100644 --- a/src/testing/exceptiontest.cs +++ b/src/testing/exceptiontest.cs @@ -2,10 +2,9 @@ namespace Python.Test { - //======================================================================== - // Supports CLR Exception unit tests. - //======================================================================== - + /// + /// Supports CLR Exception unit tests. + /// public class ExceptionTest { public int ThrowProperty @@ -78,7 +77,7 @@ public static void ThrowChainedExceptions() public class ExtendedException : OverflowException { - public ExtendedException() : base() + public ExtendedException() { } @@ -99,4 +98,4 @@ public string GetExtraInfo() return extra; } } -} \ No newline at end of file +} diff --git a/src/testing/fieldtest.cs b/src/testing/fieldtest.cs index 5860bdafb..d1bf6e983 100644 --- a/src/testing/fieldtest.cs +++ b/src/testing/fieldtest.cs @@ -1,12 +1,8 @@ -using System; - - namespace Python.Test { - //======================================================================== - // Supports units tests for field access. - //======================================================================== - + /// + /// Supports units tests for field access. + /// public class FieldTest { public FieldTest() @@ -54,4 +50,4 @@ public void Shutup() public object ObjectField; public ISpam SpamField; } -} \ No newline at end of file +} diff --git a/src/testing/generictest.cs b/src/testing/generictest.cs index 3019c1eb6..1e9c71ac6 100644 --- a/src/testing/generictest.cs +++ b/src/testing/generictest.cs @@ -1,12 +1,8 @@ -using System; -using System.Collections; - namespace Python.Test { - //======================================================================== - // Supports CLR generics unit tests. - //======================================================================== - + /// + /// Supports CLR generics unit tests. + /// public class GenericWrapper { public T value; @@ -24,20 +20,18 @@ public class GenericTypeDefinition public GenericTypeDefinition(T arg1, U arg2) { - this.value1 = arg1; - this.value2 = arg2; + value1 = arg1; + value2 = arg2; } } - public class DerivedFromOpenGeneric : - GenericTypeDefinition + public class DerivedFromOpenGeneric : GenericTypeDefinition { public W value3; - public DerivedFromOpenGeneric(int arg1, V arg2, W arg3) : - base(arg1, arg2) + public DerivedFromOpenGeneric(int arg1, V arg2, W arg3) : base(arg1, arg2) { - this.value3 = arg3; + value3 = arg3; } } @@ -131,4 +125,4 @@ public static string Overloaded(int arg1, int arg2, string arg3) return arg3; } } -} \ No newline at end of file +} diff --git a/src/testing/globaltest.cs b/src/testing/globaltest.cs index 887668d96..83a2bc439 100644 --- a/src/testing/globaltest.cs +++ b/src/testing/globaltest.cs @@ -1,9 +1,7 @@ -using System; - -//======================================================================== -// Supports units tests for access to types without a namespace. -//======================================================================== +/// +/// Supports units tests for access to types without a namespace. +/// public class NoNamespaceType { -} \ No newline at end of file +} diff --git a/src/testing/indexertest.cs b/src/testing/indexertest.cs index eb0381777..ae39eb2b1 100644 --- a/src/testing/indexertest.cs +++ b/src/testing/indexertest.cs @@ -1,12 +1,10 @@ -using System; using System.Collections; namespace Python.Test { - //======================================================================== - // Supports units tests for indexer access. - //======================================================================== - + /// + /// Supports units tests for indexer access. + /// public class IndexerBase { protected Hashtable t; @@ -377,8 +375,7 @@ public MultiTypeIndexerTest() : base() { get { - string key = i1.ToString() + i2.ToString() + - i3.GetHashCode().ToString(); + string key = i1.ToString() + i2.ToString() + i3.GetHashCode().ToString(); object value = t[key]; if (value != null) { @@ -388,8 +385,7 @@ public MultiTypeIndexerTest() : base() } set { - string key = i1.ToString() + i2.ToString() + - i3.GetHashCode().ToString(); + string key = i1.ToString() + i2.ToString() + i3.GetHashCode().ToString(); t[key] = value; } } @@ -415,4 +411,4 @@ public MultiDefaultKeyIndexerTest() : base() } } } -} \ No newline at end of file +} diff --git a/src/testing/interfacetest.cs b/src/testing/interfacetest.cs index b35ca81a8..2c24596bc 100644 --- a/src/testing/interfacetest.cs +++ b/src/testing/interfacetest.cs @@ -1,11 +1,8 @@ -using System; - namespace Python.Test { - //======================================================================== - // Supports CLR class unit tests. - //======================================================================== - + /// + /// Supports CLR class unit tests. + /// public interface IPublicInterface { } @@ -62,4 +59,4 @@ private interface IPrivate { } } -} \ No newline at end of file +} diff --git a/src/testing/methodtest.cs b/src/testing/methodtest.cs index 675b1577c..83dc907c0 100644 --- a/src/testing/methodtest.cs +++ b/src/testing/methodtest.cs @@ -1,13 +1,11 @@ using System; using System.IO; -using System.Collections.Generic; namespace Python.Test { - //======================================================================== - // Supports units tests for method access. - //======================================================================== - + /// + /// Supports units tests for method access. + /// public class MethodTest { public MethodTest() @@ -55,10 +53,9 @@ private static string PrivateStaticMethod() } - //=================================================================== - // Methods to support specific argument conversion unit tests - //=================================================================== - + /// + /// Methods to support specific argument conversion unit tests + /// public TypeCode TestEnumConversion(TypeCode v) { return v; @@ -104,8 +101,7 @@ public static int[] TestOneArgWithParams(string s, params int[] args) return args; } - public static int[] TestTwoArgWithParams(string s, string x, - params int[] args) + public static int[] TestTwoArgWithParams(string s, string x, params int[] args) { return args; } @@ -120,6 +116,71 @@ public static int[] TestOverloadedParams(int v, int[] args) return args; } + public static string TestOverloadedNoObject(int i) + { + return "Got int"; + } + + public static string TestOverloadedObject(int i) + { + return "Got int"; + } + + public static string TestOverloadedObject(object o) + { + return "Got object"; + } + + public static string TestOverloadedObjectTwo(int a, int b) + { + return "Got int-int"; + } + + public static string TestOverloadedObjectTwo(string a, string b) + { + return "Got string-string"; + } + + public static string TestOverloadedObjectTwo(string a, int b) + { + return "Got string-int"; + } + + public static string TestOverloadedObjectTwo(string a, object b) + { + return "Got string-object"; + } + + public static string TestOverloadedObjectTwo(int a, object b) + { + return "Got int-object"; + } + + public static string TestOverloadedObjectTwo(object a, int b) + { + return "Got object-int"; + } + + public static string TestOverloadedObjectTwo(object a, object b) + { + return "Got object-object"; + } + + public static string TestOverloadedObjectTwo(int a, string b) + { + return "Got int-string"; + } + + public static string TestOverloadedObjectThree(object a, int b) + { + return "Got object-int"; + } + + public static string TestOverloadedObjectThree(int a, object b) + { + return "Got int-object"; + } + public static bool TestStringOutParams(string s, out string s1) { s1 = "output string"; @@ -156,13 +217,13 @@ public static bool TestValueRefParams(string s, ref int i1) public static bool TestObjectOutParams(object o, out object o1) { - o1 = new System.Exception("test"); + o1 = new Exception("test"); return true; } public static bool TestObjectRefParams(object o, ref object o1) { - o1 = new System.Exception("test"); + o1 = new Exception("test"); return true; } @@ -386,218 +447,182 @@ public static ISayHello1[] Overloaded(ISayHello1[] v) return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper Overloaded( - GenericWrapper v) + public static GenericWrapper Overloaded(GenericWrapper v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } - public static GenericWrapper[] Overloaded( - GenericWrapper[] v) + public static GenericWrapper[] Overloaded(GenericWrapper[] v) { return v; } @@ -616,6 +641,16 @@ public static int Overloaded(int i, string s) { return i; } + + public static string CaseSensitive() + { + return "CaseSensitive"; + } + + public static string Casesensitive() + { + return "Casesensitive"; + } } @@ -630,4 +665,4 @@ public string PublicMethod(string echo) return echo; } } -} \ No newline at end of file +} diff --git a/src/testing/moduletest.cs b/src/testing/moduletest.cs index ca75a1313..2df5269f3 100644 --- a/src/testing/moduletest.cs +++ b/src/testing/moduletest.cs @@ -1,16 +1,21 @@ using System; +using System.Reflection; using System.Threading; -namespace Python.Test { - public class ModuleTest { +namespace Python.Test +{ + public class ModuleTest + { private static Thread _thread; public static void RunThreads() { - _thread = new Thread(() => { - var appdomain = AppDomain.CurrentDomain; - var assemblies = appdomain.GetAssemblies(); - foreach (var assembly in assemblies) { + _thread = new Thread(() => + { + AppDomain appdomain = AppDomain.CurrentDomain; + Assembly[] assemblies = appdomain.GetAssemblies(); + foreach (Assembly assembly in assemblies) + { assembly.GetTypes(); } }); diff --git a/src/testing/propertytest.cs b/src/testing/propertytest.cs index f01c02e0b..f54fd8bb5 100644 --- a/src/testing/propertytest.cs +++ b/src/testing/propertytest.cs @@ -1,18 +1,15 @@ -using System; - namespace Python.Test { - //======================================================================== - // Supports units tests for property access. - //======================================================================== - + /// + /// Supports units tests for property access. + /// public class PropertyTest { public PropertyTest() { } - int _public_property = 0; + private int _public_property = 0; public int PublicProperty { @@ -20,7 +17,7 @@ public int PublicProperty set { _public_property = value; } } - static int _public_static_property = 0; + private static int _public_static_property = 0; public static int PublicStaticProperty { @@ -28,7 +25,7 @@ public static int PublicStaticProperty set { _public_static_property = value; } } - int _protected_property = 0; + private int _protected_property = 0; protected int ProtectedProperty { @@ -36,7 +33,7 @@ protected int ProtectedProperty set { _protected_property = value; } } - static int _protected_static_property = 0; + private static int _protected_static_property = 0; protected static int ProtectedStaticProperty { @@ -44,7 +41,7 @@ protected static int ProtectedStaticProperty set { _protected_static_property = value; } } - int _internal_property = 0; + private int _internal_property = 0; internal int InternalProperty { @@ -52,7 +49,7 @@ internal int InternalProperty set { _internal_property = value; } } - static int _internal_static_property = 0; + private static int _internal_static_property = 0; internal static int InternalStaticProperty { @@ -60,7 +57,7 @@ internal static int InternalStaticProperty set { _internal_static_property = value; } } - int _private_property = 0; + private int _private_property = 0; private int PrivateProperty { @@ -68,7 +65,7 @@ private int PrivateProperty set { _private_property = value; } } - static int _private_static_property = 0; + private static int _private_static_property = 0; private static int PrivateStaticProperty { @@ -76,7 +73,7 @@ private static int PrivateStaticProperty set { _private_static_property = value; } } - ShortEnum _enum_property = ShortEnum.Zero; + private ShortEnum _enum_property = ShortEnum.Zero; public ShortEnum EnumProperty { @@ -84,4 +81,4 @@ public ShortEnum EnumProperty set { _enum_property = value; } } } -} \ No newline at end of file +} diff --git a/src/testing/subclasstest.cs b/src/testing/subclasstest.cs index 2b61be254..9817d865e 100644 --- a/src/testing/subclasstest.cs +++ b/src/testing/subclasstest.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; namespace Python.Test { @@ -14,14 +12,14 @@ public interface IInterfaceTest string bar(string s, int i); // test events on interfaces - event TestEventHandler TestEvent; + event EventHandlerTest TestEvent; void OnTestEvent(int value); } public class SubClassTest : IInterfaceTest { - public event TestEventHandler TestEvent; + public event EventHandlerTest TestEvent; public SubClassTest() { @@ -60,7 +58,9 @@ public static IList test_list(SubClassTest x) public virtual void OnTestEvent(int value) { if (null != TestEvent) - TestEvent(this, new TestEventArgs(value)); + { + TestEvent(this, new EventArgsTest(value)); + } } } @@ -70,12 +70,11 @@ public class SubClass : RecursiveInheritance { public void SomeMethod() { - } } } - public class TestFunctions + public class FunctionsTest { public static string test_foo(IInterfaceTest x) { @@ -92,7 +91,7 @@ public static string test_bar(IInterfaceTest x, string s, int i) // test instances can be constructed in managed code public static IInterfaceTest create_instance(Type t) { - return (IInterfaceTest)t.GetConstructor(new Type[] { }).Invoke(new Object[] { }); + return (IInterfaceTest)t.GetConstructor(new Type[] { }).Invoke(new object[] { }); } // test instances pass through managed code unchanged @@ -104,7 +103,7 @@ public static IInterfaceTest pass_through(IInterfaceTest s) public static int test_event(IInterfaceTest x, int value) { // reuse the event handler from eventtest.cs - EventTest et = new EventTest(); + var et = new EventTest(); x.TestEvent += et.GenericHandler; // raise the event (should trigger both python and managed handlers) diff --git a/src/testing/threadtest.cs b/src/testing/threadtest.cs index 0a4f46ccc..2825c3fef 100644 --- a/src/testing/threadtest.cs +++ b/src/testing/threadtest.cs @@ -1,13 +1,11 @@ using System; -using System.Collections; using Python.Runtime; namespace Python.Test { - //======================================================================== - // Supports CLR threading / reentrancy unit tests. - //======================================================================== - + /// + /// Supports CLR threading / reentrant unit tests. + /// public class ThreadTest { private static PyObject module; @@ -24,10 +22,11 @@ public class ThreadTest "\n"; - // This method calls back into the CPython runtime - tests - // call this from Python to check that we don't hang on - // nested transitions from managed to Python code and back. - + /// + /// This method calls back into the CPython runtime - tests + /// call this from Python to check that we don't hang on + /// nested transitions from managed to Python code and back. + /// public static string CallEchoString(string arg) { IntPtr gs = PythonEngine.AcquireLock(); @@ -38,9 +37,9 @@ public static string CallEchoString(string arg) module = PythonEngine.ModuleFromString("tt", testmod); } PyObject func = module.GetAttr("echostring"); - PyString parg = new PyString(arg); + var parg = new PyString(arg); PyObject temp = func.Invoke(parg); - string result = (string)temp.AsManagedObject(typeof(String)); + var result = (string)temp.AsManagedObject(typeof(string)); func.Dispose(); parg.Dispose(); temp.Dispose(); @@ -63,9 +62,9 @@ public static string CallEchoString2(string arg) } PyObject func = module.GetAttr("echostring2"); - PyString parg = new PyString(arg); + var parg = new PyString(arg); PyObject temp = func.Invoke(parg); - string result = (string)temp.AsManagedObject(typeof(String)); + var result = (string)temp.AsManagedObject(typeof(string)); func.Dispose(); parg.Dispose(); temp.Dispose(); @@ -77,4 +76,4 @@ public static string CallEchoString2(string arg) } } } -} \ No newline at end of file +} diff --git a/src/tests/PyImportTest/test/one.py b/src/tests/PyImportTest/test/one.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/tests/__init__.py b/src/tests/__init__.py new file mode 100644 index 000000000..40a96afc6 --- /dev/null +++ b/src/tests/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/src/tests/_compat.py b/src/tests/_compat.py new file mode 100644 index 000000000..3751ca013 --- /dev/null +++ b/src/tests/_compat.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- + +"""Python 2.7, 3.3+ compatibility module. + +Using Python 3 syntax to encourage upgrade unless otherwise noted. +""" + +import operator +import subprocess +import sys +import types + +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + +if PY3: + import _thread as thread # Using PY2 name + import pickle + from collections import UserList + + indexbytes = operator.getitem + input = input + + string_types = str, + binary_type = bytes + text_type = str + + DictProxyType = type(object.__dict__) + ClassType = type + + # No PY3 equivalents, use PY2 name + long = int + unichr = chr + unicode = str + + # from nowhere import Nothing + cmp = lambda a, b: (a > b) - (a < b) # No PY3 equivalent + map = map + range = range + zip = zip + +elif PY2: + import thread # Using PY2 name + import cPickle as pickle + from UserList import UserList + + indexbytes = lambda buf, i: ord(buf[i]) + input = raw_input + + string_types = str, unicode + bytes_type = str + text_type = unicode + + DictProxyType = types.DictProxyType + ClassType = types.ClassType + + # No PY3 equivalents, use PY2 name + long = long + unichr = unichr + unicode = unicode + + from itertools import izip, imap + cmp = cmp + map = imap + range = xrange + zip = izip + + +def check_output(*args, **kwargs): + """Check output wrapper for PY2/PY3 compatibility""" + output = subprocess.check_output(*args, **kwargs) + if PY2: + return output + return output.decode("ascii") diff --git a/src/tests/_missing_import.py b/src/tests/_missing_import.py new file mode 100644 index 000000000..a104cda49 --- /dev/null +++ b/src/tests/_missing_import.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +import this_package_should_never_exist_ever diff --git a/src/tests/conftest.py b/src/tests/conftest.py new file mode 100644 index 000000000..a93326c51 --- /dev/null +++ b/src/tests/conftest.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# TODO: move tests one out of src to project root. +# TODO: travis has numpy on their workers. Maybe add tests? + +"""Helpers for testing.""" + +import ctypes +import os +import sys +import sysconfig + +import pytest +import clr + +# Add path for `Python.Test` +cwd = os.path.dirname(__file__) +fixtures_path = os.path.join(cwd, "fixtures") +sys.path.append(fixtures_path) + +# Add References for tests +clr.AddReference("Python.Test") +clr.AddReference("System.Collections") +clr.AddReference("System.Data") + + +def pytest_report_header(config): + """Generate extra report headers""" + # FIXME: https://github.com/pytest-dev/pytest/issues/2257 + is_64bits = sys.maxsize > 2**32 + arch = "x64" if is_64bits else "x86" + ucs = ctypes.sizeof(ctypes.c_wchar) + libdir = sysconfig.get_config_var("LIBDIR") + shared = bool(sysconfig.get_config_var("Py_ENABLE_SHARED")) + + header = ("Arch: {arch}, UCS: {ucs}, LIBDIR: {libdir}, " + "Py_ENABLE_SHARED: {shared}".format(**locals())) + return header + + +@pytest.fixture() +def filepath(): + """Returns full filepath for file in `fixtures` directory.""" + + def make_filepath(filename): + # http://stackoverflow.com/questions/18011902/parameter-to-a-fixture + return os.path.join(fixtures_path, filename) + + return make_filepath diff --git a/src/tests/PyImportTest/__init__.py b/src/tests/fixtures/.gitkeep similarity index 100% rename from src/tests/PyImportTest/__init__.py rename to src/tests/fixtures/.gitkeep diff --git a/src/tests/fixtures/argv-fixture.py b/src/tests/fixtures/argv-fixture.py new file mode 100644 index 000000000..d56dea4e0 --- /dev/null +++ b/src/tests/fixtures/argv-fixture.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +"""Helper script to test argv. +Ensures that argv isn't modified after importing clr. +For more details see GH#404 - argv not found""" + +from __future__ import print_function + +import sys +import clr + +print(sys.argv) diff --git a/src/tests/PyImportTest/test/__init__.py b/src/tests/fixtures/netstandard2.0/.gitkeep similarity index 100% rename from src/tests/PyImportTest/test/__init__.py rename to src/tests/fixtures/netstandard2.0/.gitkeep diff --git a/src/tests/leaktest.py b/src/tests/leaktest.py index 383da87c8..05b76e867 100644 --- a/src/tests/leaktest.py +++ b/src/tests/leaktest.py @@ -1,9 +1,22 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# FIXME: TypeError: 'EventBinding' object is not callable + from __future__ import print_function -import System + +import clr import gc +import sys + +import System + +from ._compat import range +from .utils import (CallableHandler, ClassMethodHandler, GenericHandler, + HelloClass, StaticMethodHandler, VarCallableHandler, + VariableArgsHandler, hello_func) -class LeakTest: +class LeakTest(object): """A leak-check test for the objects implemented in the managed runtime. For each kind of object tested, memory should reach a particular level after warming up and stay essentially the @@ -30,10 +43,10 @@ def end_test(self): end = System.Environment.WorkingSet diff = end - start if diff > 0: - diff = '+%d' % diff + diff = '+{0}'.format(diff) else: - diff = '%d' % diff - print(" start: %d end: %d diff: %s" % (start, end, diff)) + diff = '{0}'.format(diff) + print(" start: {0} end: {1} diff: {2}".format(start, end, diff)) print("") def run(self): @@ -44,17 +57,16 @@ def run(self): self.testDelegates() def report(self): - import sys, gc gc.collect() dicttype = type({}) for item in gc.get_objects(): if type(item) != dicttype: print(item, sys.getrefcount(item)) - def testModules(self): + def test_modules(self): self.notify("Running module leak check...") - for i in xrange(self.count): + for i in range(self.count): if i == 10: self.start_test() @@ -66,14 +78,13 @@ def testModules(self): self.end_test() - def testClasses(self): + def test_classes(self): from System.Collections import Hashtable from Python.Test import StringDelegate - from System import Int32 self.notify("Running class leak check...") - for i in xrange(self.count): + for i in range(self.count): if i == 10: self.start_test() @@ -82,21 +93,21 @@ def testClasses(self): del x # Value type - x = Int32(99) + x = System.Int32(99) del x # Delegate type - x = StringDelegate(hello) + x = StringDelegate(hello_func) del x self.end_test() - def testEnumerations(self): - from Python import Test + def test_enumerations(self): + import Python.Test as Test self.notify("Running enum leak check...") - for i in xrange(self.count): + for i in range(self.count): if i == 10: self.start_test() @@ -126,12 +137,12 @@ def testEnumerations(self): self.end_test() - def testEvents(self): - from Python.Test import EventTest, TestEventArgs + def test_events(self): + from Python.Test import EventTest, EventArgsTest self.notify("Running event leak check...") - for i in xrange(self.count): + for i in range(self.count): if i == 10: self.start_test() @@ -140,28 +151,28 @@ def testEvents(self): # Instance method event handler handler = GenericHandler() testob.PublicEvent += handler.handler - testob.PublicEvent(testob, TestEventArgs(10)) + testob.PublicEvent(testob, EventArgsTest(10)) testob.PublicEvent -= handler.handler del handler # Vararg method event handler handler = VariableArgsHandler() testob.PublicEvent += handler.handler - testob.PublicEvent(testob, TestEventArgs(10)) + testob.PublicEvent(testob, EventArgsTest(10)) testob.PublicEvent -= handler.handler del handler # Callable object event handler handler = CallableHandler() testob.PublicEvent += handler - testob.PublicEvent(testob, TestEventArgs(10)) + testob.PublicEvent(testob, EventArgsTest(10)) testob.PublicEvent -= handler del handler # Callable vararg event handler handler = VarCallableHandler() testob.PublicEvent += handler - testob.PublicEvent(testob, TestEventArgs(10)) + testob.PublicEvent(testob, EventArgsTest(10)) testob.PublicEvent -= handler del handler @@ -169,7 +180,7 @@ def testEvents(self): handler = StaticMethodHandler() StaticMethodHandler.value = None testob.PublicEvent += handler.handler - testob.PublicEvent(testob, TestEventArgs(10)) + testob.PublicEvent(testob, EventArgsTest(10)) testob.PublicEvent -= handler.handler del handler @@ -177,46 +188,45 @@ def testEvents(self): handler = ClassMethodHandler() ClassMethodHandler.value = None testob.PublicEvent += handler.handler - testob.PublicEvent(testob, TestEventArgs(10)) + testob.PublicEvent(testob, EventArgsTest(10)) testob.PublicEvent -= handler.handler del handler # Managed instance event handler testob.PublicEvent += testob.GenericHandler - testob.PublicEvent(testob, TestEventArgs(10)) + testob.PublicEvent(testob, EventArgsTest(10)) testob.PublicEvent -= testob.GenericHandler # Static managed event handler testob.PublicEvent += EventTest.StaticHandler - testob.PublicEvent(testob, TestEventArgs(10)) + testob.PublicEvent(testob, EventArgsTest(10)) testob.PublicEvent -= EventTest.StaticHandler # Function event handler - dict = {'value': None} + dict_ = {'value': None} - def handler(sender, args, dict=dict): - dict['value'] = args.value + def handler(sender, args, dict_=dict_): + dict_['value'] = args.value testob.PublicEvent += handler - testob.PublicEvent(testob, TestEventArgs(10)) + testob.PublicEvent(testob, EventArgsTest(10)) testob.PublicEvent -= handler del handler self.end_test() - def testDelegates(self): + def test_delegates(self): from Python.Test import DelegateTest, StringDelegate - import System self.notify("Running delegate leak check...") - for i in xrange(self.count): + for i in range(self.count): if i == 10: self.start_test() # Delegate from function testob = DelegateTest() - d = StringDelegate(hello) + d = StringDelegate(hello_func) testob.CallStringDelegate(d) testob.stringDelegate = d testob.stringDelegate() @@ -225,7 +235,7 @@ def testDelegates(self): del d # Delegate from instance method - inst = Hello() + inst = HelloClass() testob = DelegateTest() d = StringDelegate(inst.hello) testob.CallStringDelegate(d) @@ -238,7 +248,7 @@ def testDelegates(self): # Delegate from static method testob = DelegateTest() - d = StringDelegate(Hello.s_hello) + d = StringDelegate(HelloClass.s_hello) testob.CallStringDelegate(d) testob.stringDelegate = d testob.stringDelegate() @@ -248,7 +258,7 @@ def testDelegates(self): # Delegate from class method testob = DelegateTest() - d = StringDelegate(Hello.c_hello) + d = StringDelegate(HelloClass.c_hello) testob.CallStringDelegate(d) testob.stringDelegate = d testob.stringDelegate() @@ -257,7 +267,7 @@ def testDelegates(self): del d # Delegate from callable object - inst = Hello() + inst = HelloClass() testob = DelegateTest() d = StringDelegate(inst) testob.CallStringDelegate(d) @@ -290,7 +300,7 @@ def testDelegates(self): # Nested delegates testob = DelegateTest() - d1 = StringDelegate(hello) + d1 = StringDelegate(hello_func) d2 = StringDelegate(d1) testob.CallStringDelegate(d2) testob.stringDelegate = d2 @@ -302,8 +312,8 @@ def testDelegates(self): # Multicast delegates testob = DelegateTest() - d1 = StringDelegate(hello) - d2 = StringDelegate(hello) + d1 = StringDelegate(hello_func) + d2 = StringDelegate(hello_func) md = System.Delegate.Combine(d1, d2) testob.CallStringDelegate(md) testob.stringDelegate = md @@ -317,92 +327,6 @@ def testDelegates(self): self.end_test() -class GenericHandler: - """A generic handler to test event callbacks.""" - - def __init__(self): - self.value = None - - def handler(self, sender, args): - self.value = args.value - - -class VariableArgsHandler: - """A variable args handler to test event callbacks.""" - - def __init__(self): - self.value = None - - def handler(self, *args): - ob, eventargs = args - self.value = eventargs.value - - -class CallableHandler: - """A callable handler to test event callbacks.""" - - def __init__(self): - self.value = None - - def __call__(self, sender, args): - self.value = args.value - - -class VarCallableHandler: - """A variable args callable handler to test event callbacks.""" - - def __init__(self): - self.value = None - - def __call__(self, *args): - ob, eventargs = args - self.value = eventargs.value - - -class StaticMethodHandler(object): - """A static method handler to test event callbacks.""" - - value = None - - def handler(sender, args): - StaticMethodHandler.value = args.value - - handler = staticmethod(handler) - - -class ClassMethodHandler(object): - """A class method handler to test event callbacks.""" - - value = None - - def handler(cls, sender, args): - cls.value = args.value - - handler = classmethod(handler) - - -class Hello: - def hello(self): - return "hello" - - def __call__(self): - return "hello" - - def s_hello(): - return "hello" - - s_hello = staticmethod(s_hello) - - def c_hello(cls): - return "hello" - - c_hello = classmethod(c_hello) - - -def hello(): - return "hello" - - if __name__ == '__main__': test = LeakTest() test.run() diff --git a/src/tests/profile.py b/src/tests/profile.py index 6117b9616..4af3589e8 100644 --- a/src/tests/profile.py +++ b/src/tests/profile.py @@ -1,26 +1,37 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# FIXME: FAIL: testImplicitAssemblyLoad AssertionError: 0 != 1 + """Run all of the unit tests for this package over and over, - in order to provide for better profiling.""" + in order to provide for better profiling. +""" + from __future__ import print_function +import gc +import os +import sys +import time -def main(): - import sys, os, gc, time +import runtests +from ._compat import range + +def main(): dirname = os.path.split(__file__) sys.path.append(dirname) - import runtests gc.set_debug(gc.DEBUG_LEAK) start = time.clock() for i in range(50): - print('iteration: %d' % i) + print('iteration: {0:d}'.format(i)) runtests.main() stop = time.clock() took = str(stop - start) - print('Total Time: %s' % took) + print('Total Time: {0}'.format(took)) for item in gc.get_objects(): print(item, sys.getrefcount(item)) @@ -28,4 +39,3 @@ def main(): if __name__ == '__main__': main() - sys.exit(0) diff --git a/src/tests/runtests.py b/src/tests/runtests.py index 660d3442d..8011d05e6 100644 --- a/src/tests/runtests.py +++ b/src/tests/runtests.py @@ -1,11 +1,14 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + """Run all of the unit tests for this package.""" -import os +from __future__ import print_function + import sys -import unittest -import warnfilter +import pytest -warnfilter.addClrWarnfilter() +from ._compat import input try: import System @@ -13,56 +16,25 @@ print("Load clr import hook") import clr -test_modules = ( - 'test_module', # Passes on its own, but not here if - # other test modules that import System.Windows.Forms - # run first. They must not do module level import/AddReference() - # of the System.Windows.Forms namespace. - 'test_suite', - 'test_event', - 'test_constructors', - 'test_enum', - 'test_method', - - 'test_exceptions', - 'test_compat', - 'test_generic', - 'test_conversion', - 'test_class', - 'test_interface', - 'test_field', - 'test_property', - 'test_indexer', - 'test_delegate', - 'test_array', - 'test_thread' -) - - -def removePyc(): - path = os.path.dirname(os.path.abspath(__file__)) - for name in test_modules: - pyc = os.path.join(path, "%s.pyc" % name) - if os.path.isfile(pyc): - os.unlink(pyc) + clr.AddReference("Python.Test") + clr.AddReference("System.Collections") + clr.AddReference("System.Data") + clr.AddReference("System.Management") def main(verbosity=1): - removePyc() - - suite = unittest.TestSuite() - - for name in test_modules: - module = __import__(name) - suite.addTests((module.test_suite(),)) + # test_module passes on its own, but not here if + # other test modules that import System.Windows.Forms + # run first. They must not do module level import/AddReference() + # of the System.Windows.Forms namespace. - result = unittest.TextTestRunner(verbosity=verbosity).run(suite) - if not result.wasSuccessful(): - raise Exception("Tests failed") + # FIXME: test_engine has tests that are being skipped. + # FIXME: test_subclass has tests that are being skipped. + pytest.main() if __name__ == '__main__': - main(1) + main() if '--pause' in sys.argv: print("Press enter to continue") - raw_input() + input() diff --git a/src/tests/stress.py b/src/tests/stress.py index dba74a6df..c6fa8b7e3 100644 --- a/src/tests/stress.py +++ b/src/tests/stress.py @@ -1,15 +1,27 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# FIXME: FAIL: testImplicitAssemblyLoad AssertionError: 0 != 1 + """ Run all of the unit tests for this package multiple times in a highly -multithreaded way to stress the system. This makes it possible to look +multi-threaded way to stress the system. This makes it possible to look for memory leaks and threading issues and provides a good target for a profiler to accumulate better data. """ + from __future__ import print_function -import sys, os, gc, time, threading, thread +import gc +import os +import sys +import threading +import time +from ._compat import range, thread +from .utils import dprint -class StressTest: + +class StressTest(object): def __init__(self): self.dirname = os.path.split(__file__)[0] sys.path.append(self.dirname) @@ -18,53 +30,48 @@ def __init__(self): self.module = runtests self.done = [] - def dprint(self, msg): - # Debugging helper to trace thread-related tests. - if 1: print(msg) - - def markStart(self): + def mark_start(self): self._start = time.clock() - def markFinish(self): + def mark_finish(self): self._finish = time.clock() def elapsed(self): return self._finish - self._start - def printGCReport(self): + def print_gc_report(self): for item in gc.get_objects(): print(item, sys.getrefcount(item)) - def runThread(self, iterations): + def run_thread(self, iterations): thread_id = thread.get_ident() - self.dprint("thread %s starting..." % thread_id) + dprint("thread {0} starting...".format(thread_id)) time.sleep(0.1) for i in range(iterations): - self.dprint("thread %s iter %d start" % (thread_id, i)) + dprint("thread {0} iter {1} start".format(thread_id, i)) self.module.main() - self.dprint("thread %s iter %d end" % (thread_id, i)) + dprint("thread {0} iter {1} end".format(thread_id, i)) self.done.append(None) - self.dprint("thread %s done" % thread_id) + dprint("thread {0} done".format(thread_id)) - def stressTest(self, iterations=1, threads=1): + def stress_test(self, iterations=1, threads=1): args = (iterations,) - self.markStart() - for i in range(threads): - thread = threading.Thread(target=self.runThread, args=args) + self.mark_start() + for _ in range(threads): + thread = threading.Thread(target=self.run_thread, args=args) thread.start() while len(self.done) < (iterations * threads): - self.dprint(len(self.done)) + dprint(len(self.done)) time.sleep(0.1) - self.markFinish() + self.mark_finish() took = self.elapsed() - self.printGCReport() + self.print_gc_report() def main(): test = StressTest() - test.stressTest(2, 10) + test.stress_test(2, 10) if __name__ == '__main__': main() - sys.exit(0) diff --git a/src/tests/stresstest.py b/src/tests/stresstest.py index bdb7c3e70..74b863bdc 100644 --- a/src/tests/stresstest.py +++ b/src/tests/stresstest.py @@ -1,36 +1,57 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# FIXME: FAIL: testImplicitAssemblyLoad AssertionError: 0 != 1 + """Basic stress test.""" +from __future__ import print_function + +import gc +import time +import unittest +# import pdb + +from ._compat import range + +try: + import System +except ImportError: + print("Load clr import hook") + import clr + clr.AddReference("Python.Test") + clr.AddReference("System.Collections") + clr.AddReference("System.Data") + clr.AddReference("System.Management") + def main(): - import time start = time.clock() for i in range(2000): print(i) for name in ( - 'test_module', - 'test_conversion', - # 'test_class', - 'test_interface', - 'test_enum', - 'test_field', - 'test_property', - 'test_indexer', - 'test_event', - 'test_method', - # 'test_delegate', - 'test_array', + 'test_module', + 'test_conversion', + # 'test_class', + 'test_interface', + 'test_enum', + 'test_field', + 'test_property', + 'test_indexer', + 'test_event', + 'test_method', + # 'test_delegate', + 'test_array', ): module = __import__(name) - module.main() + unittest.TextTestRunner().run(module.test_suite()) - # import pdb; pdb.set_trace() + # pdb.set_trace() stop = time.clock() took = str(stop - start) - print 'Total Time: %s' % took + print('Total Time: {0}'.format(took)) - import gc for i in gc.get_objects(): print(i) diff --git a/src/tests/test_array.py b/src/tests/test_array.py index 9e396d7ed..7ccadddff 100644 --- a/src/tests/test_array.py +++ b/src/tests/test_array.py @@ -1,1488 +1,1339 @@ -import sys, os, string, unittest, types -import Python.Test as Test -import System -import six - -if six.PY3: - long = int - unichr = chr - - -class ArrayTests(unittest.TestCase): - """Test support for managed arrays.""" - - def testPublicArray(self): - """Test public arrays.""" - object = Test.PublicArrayTest() - items = object.items - - self.assertTrue(len(items) == 5) - - self.assertTrue(items[0] == 0) - self.assertTrue(items[4] == 4) - - items[0] = 8 - self.assertTrue(items[0] == 8) - - items[4] = 9 - self.assertTrue(items[4] == 9) - - items[-4] = 0 - self.assertTrue(items[-4] == 0) - - items[-1] = 4 - self.assertTrue(items[-1] == 4) - - def testProtectedArray(self): - """Test protected arrays.""" - object = Test.ProtectedArrayTest() - items = object.items - - self.assertTrue(len(items) == 5) - - self.assertTrue(items[0] == 0) - self.assertTrue(items[4] == 4) - - items[0] = 8 - self.assertTrue(items[0] == 8) - - items[4] = 9 - self.assertTrue(items[4] == 9) - - items[-4] = 0 - self.assertTrue(items[-4] == 0) - - items[-1] = 4 - self.assertTrue(items[-1] == 4) - - def testInternalArray(self): - """Test internal arrays.""" - - def test(): - object = Test.InternalArrayTest() - items = object.items - - self.assertRaises(AttributeError, test) +# -*- coding: utf-8 -*- - def testPrivateArray(self): - """Test private arrays.""" +"""Test support for managed arrays.""" - def test(): - object = Test.PrivateArrayTest() - items = object.items - - self.assertRaises(AttributeError, test) - - def testArrayBoundsChecking(self): - """Test array bounds checking.""" - - object = Test.Int32ArrayTest() - items = object.items - - self.assertTrue(items[0] == 0) - self.assertTrue(items[1] == 1) - self.assertTrue(items[2] == 2) - self.assertTrue(items[3] == 3) - self.assertTrue(items[4] == 4) - - self.assertTrue(items[-5] == 0) - self.assertTrue(items[-4] == 1) - self.assertTrue(items[-3] == 2) - self.assertTrue(items[-2] == 3) - self.assertTrue(items[-1] == 4) - - def test(): - object = Test.Int32ArrayTest() - object.items[5] - - self.assertRaises(IndexError, test) - - def test(): - object = Test.Int32ArrayTest() - object.items[5] = 0 - - self.assertRaises(IndexError, test) - - def test(): - object = Test.Int32ArrayTest() - items[-6] - - self.assertRaises(IndexError, test) - - def test(): - object = Test.Int32ArrayTest() - items[-6] = 0 - - self.assertRaises(IndexError, test) - - def testArrayContains(self): - """Test array support for __contains__.""" - - object = Test.Int32ArrayTest() - items = object.items - - self.assertTrue(0 in items) - self.assertTrue(1 in items) - self.assertTrue(2 in items) - self.assertTrue(3 in items) - self.assertTrue(4 in items) - - self.assertFalse(5 in items) # "H:\Python27\Lib\unittest\case.py", line 592, in deprecated_func, - self.assertFalse(-1 in items) # TypeError: int() argument must be a string or a number, not 'NoneType' - self.assertFalse(None in items) # which threw ^ here which is a little odd. - # But when run from runtests.py. Not when this module ran by itself. - - def testBooleanArray(self): - """Test boolean arrays.""" - object = Test.BooleanArrayTest() - items = object.items - - self.assertTrue(len(items) == 5) +import Python.Test as Test +import System +import pytest - self.assertTrue(items[0] == True) - self.assertTrue(items[1] == False) - self.assertTrue(items[2] == True) - self.assertTrue(items[3] == False) - self.assertTrue(items[4] == True) +from ._compat import PY2, UserList, long, range, unichr - items[0] = False - self.assertTrue(items[0] == False) - items[0] = True - self.assertTrue(items[0] == True) +def test_public_array(): + """Test public arrays.""" + ob = Test.PublicArrayTest() + items = ob.items - def test(): - object = Test.ByteArrayTest() - v = object.items["wrong"] + assert len(items) == 5 - self.assertRaises(TypeError, test) + assert items[0] == 0 + assert items[4] == 4 - def test(): - object = Test.ByteArrayTest() - object[0] = "wrong" + items[0] = 8 + assert items[0] == 8 - self.assertRaises(TypeError, test) + items[4] = 9 + assert items[4] == 9 - def testByteArray(self): - """Test byte arrays.""" - object = Test.ByteArrayTest() - items = object.items + items[-4] = 0 + assert items[-4] == 0 - self.assertTrue(len(items) == 5) + items[-1] = 4 + assert items[-1] == 4 - self.assertTrue(items[0] == 0) - self.assertTrue(items[4] == 4) - max = 255 - min = 0 +def test_protected_array(): + """Test protected arrays.""" + ob = Test.ProtectedArrayTest() + items = ob.items - items[0] = max - self.assertTrue(items[0] == max) + assert len(items) == 5 - items[0] = min - self.assertTrue(items[0] == min) + assert items[0] == 0 + assert items[4] == 4 - items[-4] = max - self.assertTrue(items[-4] == max) + items[0] = 8 + assert items[0] == 8 - items[-1] = min - self.assertTrue(items[-1] == min) + items[4] = 9 + assert items[4] == 9 - def test(): - object = Test.ByteArrayTest() - object.items[0] = max + 1 + items[-4] = 0 + assert items[-4] == 0 - self.assertRaises(OverflowError, test) + items[-1] = 4 + assert items[-1] == 4 - def test(): - object = Test.ByteArrayTest() - object.items[0] = min - 1 - self.assertRaises(OverflowError, test) +def test_internal_array(): + """Test internal arrays.""" - def test(): - object = Test.ByteArrayTest() - v = object.items["wrong"] + with pytest.raises(AttributeError): + ob = Test.InternalArrayTest() + _ = ob.items - self.assertRaises(TypeError, test) - def test(): - object = Test.ByteArrayTest() - object[0] = "wrong" +def test_private_array(): + """Test private arrays.""" - self.assertRaises(TypeError, test) + with pytest.raises(AttributeError): + ob = Test.PrivateArrayTest() + _ = ob.items - def testSByteArray(self): - """Test sbyte arrays.""" - object = Test.SByteArrayTest() - items = object.items - self.assertTrue(len(items) == 5) +def test_array_bounds_checking(): + """Test array bounds checking.""" - self.assertTrue(items[0] == 0) - self.assertTrue(items[4] == 4) + ob = Test.Int32ArrayTest() + items = ob.items - max = 127 - min = -128 + assert items[0] == 0 + assert items[1] == 1 + assert items[2] == 2 + assert items[3] == 3 + assert items[4] == 4 - items[0] = max - self.assertTrue(items[0] == max) + assert items[-5] == 0 + assert items[-4] == 1 + assert items[-3] == 2 + assert items[-2] == 3 + assert items[-1] == 4 - items[0] = min - self.assertTrue(items[0] == min) + with pytest.raises(IndexError): + ob = Test.Int32ArrayTest() + _ = ob.items[5] - items[-4] = max - self.assertTrue(items[-4] == max) + with pytest.raises(IndexError): + ob = Test.Int32ArrayTest() + ob.items[5] = 0 - items[-1] = min - self.assertTrue(items[-1] == min) + with pytest.raises(IndexError): + ob = Test.Int32ArrayTest() + items[-6] - def test(): - object = Test.SByteArrayTest() - object.items[0] = max + 1 + with pytest.raises(IndexError): + ob = Test.Int32ArrayTest() + items[-6] = 0 - self.assertRaises(OverflowError, test) - def test(): - object = Test.SByteArrayTest() - object.items[0] = min - 1 +def test_array_contains(): + """Test array support for __contains__.""" - self.assertRaises(OverflowError, test) + ob = Test.Int32ArrayTest() + items = ob.items - def test(): - object = Test.SByteArrayTest() - v = object.items["wrong"] + assert 0 in items + assert 1 in items + assert 2 in items + assert 3 in items + assert 4 in items - self.assertRaises(TypeError, test) + assert not (5 in items) # "H:\Python27\Lib\unittest\case.py", line 592, in deprecated_func, + assert not (-1 in items) # TypeError: int() argument must be a string or a number, not 'NoneType' + assert not (None in items) # which threw ^ here which is a little odd. + # But when run from runtests.py. Not when this module ran by itself. - def test(): - object = Test.SByteArrayTest() - object[0] = "wrong" - self.assertRaises(TypeError, test) +def test_boolean_array(): + """Test boolean arrays.""" + ob = Test.BooleanArrayTest() + items = ob.items - def testCharArray(self): - """Test char arrays.""" - object = Test.CharArrayTest() - items = object.items + assert len(items) == 5 - self.assertTrue(len(items) == 5) + assert items[0] is True + assert items[1] is False + assert items[2] is True + assert items[3] is False + assert items[4] is True - self.assertTrue(items[0] == 'a') - self.assertTrue(items[4] == 'e') + items[0] = False + assert items[0] is False - max = unichr(65535) - min = unichr(0) + items[0] = True + assert items[0] is True - items[0] = max - self.assertTrue(items[0] == max) + with pytest.raises(TypeError): + ob = Test.ByteArrayTest() + _ = ob.items["wrong"] - items[0] = min - self.assertTrue(items[0] == min) + with pytest.raises(TypeError): + ob = Test.ByteArrayTest() + ob[0] = "wrong" - items[-4] = max - self.assertTrue(items[-4] == max) - items[-1] = min - self.assertTrue(items[-1] == min) +def test_byte_array(): + """Test byte arrays.""" + ob = Test.ByteArrayTest() + items = ob.items - def test(): - object = Test.CharArrayTest() - v = object.items["wrong"] + assert len(items) == 5 - self.assertRaises(TypeError, test) + assert items[0] == 0 + assert items[4] == 4 - def test(): - object = Test.CharArrayTest() - object[0] = "wrong" + max_ = 255 + min_ = 0 - self.assertRaises(TypeError, test) + items[0] = max_ + assert items[0] == max_ - def testInt16Array(self): - """Test Int16 arrays.""" - object = Test.Int16ArrayTest() - items = object.items + items[0] = min_ + assert items[0] == min_ - self.assertTrue(len(items) == 5) + items[-4] = max_ + assert items[-4] == max_ - self.assertTrue(items[0] == 0) - self.assertTrue(items[4] == 4) + items[-1] = min_ + assert items[-1] == min_ - max = 32767 - min = -32768 + with pytest.raises(OverflowError): + ob = Test.ByteArrayTest() + ob.items[0] = max_ + 1 - items[0] = max - self.assertTrue(items[0] == max) + with pytest.raises(OverflowError): + ob = Test.ByteArrayTest() + ob.items[0] = min_ - 1 - items[0] = min - self.assertTrue(items[0] == min) + with pytest.raises(TypeError): + ob = Test.ByteArrayTest() + _ = ob.items["wrong"] - items[-4] = max - self.assertTrue(items[-4] == max) + with pytest.raises(TypeError): + ob = Test.ByteArrayTest() + ob[0] = "wrong" - items[-1] = min - self.assertTrue(items[-1] == min) - def test(): - object = Test.Int16ArrayTest() - object.items[0] = max + 1 +def test_sbyte_array(): + """Test sbyte arrays.""" + ob = Test.SByteArrayTest() + items = ob.items - self.assertRaises(OverflowError, test) + assert len(items) == 5 - def test(): - object = Test.Int16ArrayTest() - object.items[0] = min - 1 + assert items[0] == 0 + assert items[4] == 4 - self.assertRaises(OverflowError, test) + max_ = 127 + min_ = -128 - def test(): - object = Test.Int16ArrayTest() - v = object.items["wrong"] + items[0] = max_ + assert items[0] == max_ - self.assertRaises(TypeError, test) + items[0] = min_ + assert items[0] == min_ - def test(): - object = Test.Int16ArrayTest() - object[0] = "wrong" + items[-4] = max_ + assert items[-4] == max_ - self.assertRaises(TypeError, test) + items[-1] = min_ + assert items[-1] == min_ - def testInt32Array(self): - """Test Int32 arrays.""" - object = Test.Int32ArrayTest() - items = object.items + with pytest.raises(OverflowError): + ob = Test.SByteArrayTest() + ob.items[0] = max_ + 1 - self.assertTrue(len(items) == 5) + with pytest.raises(OverflowError): + ob = Test.SByteArrayTest() + ob.items[0] = min_ - 1 - self.assertTrue(items[0] == 0) - self.assertTrue(items[4] == 4) + with pytest.raises(TypeError): + ob = Test.SByteArrayTest() + _ = ob.items["wrong"] - max = 2147483647 - min = -2147483648 + with pytest.raises(TypeError): + ob = Test.SByteArrayTest() + ob[0] = "wrong" - items[0] = max - self.assertTrue(items[0] == max) - items[0] = min - self.assertTrue(items[0] == min) +def test_char_array(): + """Test char arrays.""" + ob = Test.CharArrayTest() + items = ob.items - items[-4] = max - self.assertTrue(items[-4] == max) + assert len(items) == 5 - items[-1] = min - self.assertTrue(items[-1] == min) + assert items[0] == 'a' + assert items[4] == 'e' - def test(): - object = Test.Int32ArrayTest() - object.items[0] = max + 1 + max_ = unichr(65535) + min_ = unichr(0) - self.assertRaises(OverflowError, test) + items[0] = max_ + assert items[0] == max_ - def test(): - object = Test.Int32ArrayTest() - object.items[0] = min - 1 + items[0] = min_ + assert items[0] == min_ - self.assertRaises(OverflowError, test) + items[-4] = max_ + assert items[-4] == max_ - def test(): - object = Test.Int32ArrayTest() - v = object.items["wrong"] + items[-1] = min_ + assert items[-1] == min_ - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.CharArrayTest() + _ = ob.items["wrong"] - def test(): - object = Test.Int32ArrayTest() - object[0] = "wrong" + with pytest.raises(TypeError): + ob = Test.CharArrayTest() + ob[0] = "wrong" - self.assertRaises(TypeError, test) - def testInt64Array(self): - """Test Int64 arrays.""" - object = Test.Int64ArrayTest() - items = object.items +def test_int16_array(): + """Test Int16 arrays.""" + ob = Test.Int16ArrayTest() + items = ob.items - self.assertTrue(len(items) == 5) + assert len(items) == 5 - self.assertTrue(items[0] == 0) - self.assertTrue(items[4] == 4) + assert items[0] == 0 + assert items[4] == 4 - max = long(9223372036854775807) - min = long(-9223372036854775808) + max_ = 32767 + min_ = -32768 - items[0] = max - self.assertTrue(items[0] == max) + items[0] = max_ + assert items[0] == max_ - items[0] = min - self.assertTrue(items[0] == min) + items[0] = min_ + assert items[0] == min_ - items[-4] = max - self.assertTrue(items[-4] == max) + items[-4] = max_ + assert items[-4] == max_ - items[-1] = min - self.assertTrue(items[-1] == min) + items[-1] = min_ + assert items[-1] == min_ - def test(): - object = Test.Int64ArrayTest() - object.items[0] = max + 1 + with pytest.raises(OverflowError): + ob = Test.Int16ArrayTest() + ob.items[0] = max_ + 1 - self.assertRaises(OverflowError, test) + with pytest.raises(OverflowError): + ob = Test.Int16ArrayTest() + ob.items[0] = min_ - 1 - def test(): - object = Test.Int64ArrayTest() - object.items[0] = min - 1 + with pytest.raises(TypeError): + ob = Test.Int16ArrayTest() + _ = ob.items["wrong"] - self.assertRaises(OverflowError, test) + with pytest.raises(TypeError): + ob = Test.Int16ArrayTest() + ob[0] = "wrong" - def test(): - object = Test.Int64ArrayTest() - v = object.items["wrong"] - self.assertRaises(TypeError, test) +def test_int32_array(): + """Test Int32 arrays.""" + ob = Test.Int32ArrayTest() + items = ob.items - def test(): - object = Test.Int64ArrayTest() - object[0] = "wrong" + assert len(items) == 5 - self.assertRaises(TypeError, test) + assert items[0] == 0 + assert items[4] == 4 - def testUInt16Array(self): - """Test UInt16 arrays.""" - object = Test.UInt16ArrayTest() - items = object.items + max_ = 2147483647 + min_ = -2147483648 - self.assertTrue(len(items) == 5) + items[0] = max_ + assert items[0] == max_ - self.assertTrue(items[0] == 0) - self.assertTrue(items[4] == 4) + items[0] = min_ + assert items[0] == min_ - max = 65535 - min = 0 + items[-4] = max_ + assert items[-4] == max_ - items[0] = max - self.assertTrue(items[0] == max) + items[-1] = min_ + assert items[-1] == min_ - items[0] = min - self.assertTrue(items[0] == min) + with pytest.raises(OverflowError): + ob = Test.Int32ArrayTest() + ob.items[0] = max_ + 1 - items[-4] = max - self.assertTrue(items[-4] == max) + with pytest.raises(OverflowError): + ob = Test.Int32ArrayTest() + ob.items[0] = min_ - 1 - items[-1] = min - self.assertTrue(items[-1] == min) + with pytest.raises(TypeError): + ob = Test.Int32ArrayTest() + _ = ob.items["wrong"] - def test(): - object = Test.UInt16ArrayTest() - object.items[0] = max + 1 + with pytest.raises(TypeError): + ob = Test.Int32ArrayTest() + ob[0] = "wrong" - self.assertRaises(OverflowError, test) - def test(): - object = Test.UInt16ArrayTest() - object.items[0] = min - 1 +def test_int64_array(): + """Test Int64 arrays.""" + ob = Test.Int64ArrayTest() + items = ob.items - self.assertRaises(OverflowError, test) + assert len(items) == 5 - def test(): - object = Test.UInt16ArrayTest() - v = object.items["wrong"] + assert items[0] == 0 + assert items[4] == 4 - self.assertRaises(TypeError, test) + max_ = long(9223372036854775807) + min_ = long(-9223372036854775808) - def test(): - object = Test.UInt16ArrayTest() - object[0] = "wrong" + items[0] = max_ + assert items[0] == max_ - self.assertRaises(TypeError, test) + items[0] = min_ + assert items[0] == min_ - def testUInt32Array(self): - """Test UInt32 arrays.""" - object = Test.UInt32ArrayTest() - items = object.items + items[-4] = max_ + assert items[-4] == max_ - self.assertTrue(len(items) == 5) + items[-1] = min_ + assert items[-1] == min_ - self.assertTrue(items[0] == 0) - self.assertTrue(items[4] == 4) + with pytest.raises(OverflowError): + ob = Test.Int64ArrayTest() + ob.items[0] = max_ + 1 - max = long(4294967295) - min = 0 + with pytest.raises(OverflowError): + ob = Test.Int64ArrayTest() + ob.items[0] = min_ - 1 - items[0] = max - self.assertTrue(items[0] == max) + with pytest.raises(TypeError): + ob = Test.Int64ArrayTest() + _ = ob.items["wrong"] - items[0] = min - self.assertTrue(items[0] == min) + with pytest.raises(TypeError): + ob = Test.Int64ArrayTest() + ob[0] = "wrong" - items[-4] = max - self.assertTrue(items[-4] == max) - items[-1] = min - self.assertTrue(items[-1] == min) +def test_uint16_array(): + """Test UInt16 arrays.""" + ob = Test.UInt16ArrayTest() + items = ob.items - def test(): - object = Test.UInt32ArrayTest() - object.items[0] = max + 1 + assert len(items) == 5 - self.assertRaises(OverflowError, test) + assert items[0] == 0 + assert items[4] == 4 - def test(): - object = Test.UInt32ArrayTest() - object.items[0] = min - 1 + max_ = 65535 + min_ = 0 - self.assertRaises(OverflowError, test) + items[0] = max_ + assert items[0] == max_ - def test(): - object = Test.UInt32ArrayTest() - v = object.items["wrong"] + items[0] = min_ + assert items[0] == min_ - self.assertRaises(TypeError, test) + items[-4] = max_ + assert items[-4] == max_ - def test(): - object = Test.UInt32ArrayTest() - object[0] = "wrong" + items[-1] = min_ + assert items[-1] == min_ - self.assertRaises(TypeError, test) + with pytest.raises(OverflowError): + ob = Test.UInt16ArrayTest() + ob.items[0] = max_ + 1 - def testUInt64Array(self): - """Test UInt64 arrays.""" - object = Test.UInt64ArrayTest() - items = object.items + with pytest.raises(OverflowError): + ob = Test.UInt16ArrayTest() + ob.items[0] = min_ - 1 - self.assertTrue(len(items) == 5) + with pytest.raises(TypeError): + ob = Test.UInt16ArrayTest() + _ = ob.items["wrong"] - self.assertTrue(items[0] == 0) - self.assertTrue(items[4] == 4) + with pytest.raises(TypeError): + ob = Test.UInt16ArrayTest() + ob[0] = "wrong" - max = long(18446744073709551615) - min = 0 - items[0] = max - self.assertTrue(items[0] == max) +def test_uint32_array(): + """Test UInt32 arrays.""" + ob = Test.UInt32ArrayTest() + items = ob.items - items[0] = min - self.assertTrue(items[0] == min) + assert len(items) == 5 - items[-4] = max - self.assertTrue(items[-4] == max) + assert items[0] == 0 + assert items[4] == 4 - items[-1] = min - self.assertTrue(items[-1] == min) + max_ = long(4294967295) + min_ = 0 - def test(): - object = Test.UInt64ArrayTest() - object.items[0] = max + 1 + items[0] = max_ + assert items[0] == max_ - self.assertRaises(OverflowError, test) + items[0] = min_ + assert items[0] == min_ - def test(): - object = Test.UInt64ArrayTest() - object.items[0] = min - 1 + items[-4] = max_ + assert items[-4] == max_ - self.assertRaises(OverflowError, test) + items[-1] = min_ + assert items[-1] == min_ - def test(): - object = Test.UInt64ArrayTest() - v = object.items["wrong"] + with pytest.raises(OverflowError): + ob = Test.UInt32ArrayTest() + ob.items[0] = max_ + 1 - self.assertRaises(TypeError, test) + with pytest.raises(OverflowError): + ob = Test.UInt32ArrayTest() + ob.items[0] = min_ - 1 - def test(): - object = Test.UInt64ArrayTest() - object[0] = "wrong" + with pytest.raises(TypeError): + ob = Test.UInt32ArrayTest() + _ = ob.items["wrong"] - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.UInt32ArrayTest() + ob[0] = "wrong" - def testSingleArray(self): - """Test Single arrays.""" - object = Test.SingleArrayTest() - items = object.items - self.assertTrue(len(items) == 5) +def test_uint64_array(): + """Test UInt64 arrays.""" + ob = Test.UInt64ArrayTest() + items = ob.items - self.assertTrue(items[0] == 0.0) - self.assertTrue(items[4] == 4.0) + assert len(items) == 5 - max = 3.402823e38 - min = -3.402823e38 + assert items[0] == 0 + assert items[4] == 4 - items[0] = max - self.assertTrue(items[0] == max) + max_ = long(18446744073709551615) + min_ = 0 - items[0] = min - self.assertTrue(items[0] == min) + items[0] = max_ + assert items[0] == max_ - items[-4] = max - self.assertTrue(items[-4] == max) + items[0] = min_ + assert items[0] == min_ - items[-1] = min - self.assertTrue(items[-1] == min) + items[-4] = max_ + assert items[-4] == max_ - def test(): - object = Test.SingleArrayTest() - v = object.items["wrong"] + items[-1] = min_ + assert items[-1] == min_ - self.assertRaises(TypeError, test) + with pytest.raises(OverflowError): + ob = Test.UInt64ArrayTest() + ob.items[0] = max_ + 1 - def test(): - object = Test.SingleArrayTest() - object[0] = "wrong" + with pytest.raises(OverflowError): + ob = Test.UInt64ArrayTest() + ob.items[0] = min_ - 1 - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.UInt64ArrayTest() + _ = ob.items["wrong"] - def testDoubleArray(self): - """Test Double arrays.""" - object = Test.DoubleArrayTest() - items = object.items + with pytest.raises(TypeError): + ob = Test.UInt64ArrayTest() + ob[0] = "wrong" - self.assertTrue(len(items) == 5) - self.assertTrue(items[0] == 0.0) - self.assertTrue(items[4] == 4.0) +def test_single_array(): + """Test Single arrays.""" + ob = Test.SingleArrayTest() + items = ob.items - max = 1.7976931348623157e308 - min = -1.7976931348623157e308 + assert len(items) == 5 - items[0] = max - self.assertTrue(items[0] == max) + assert items[0] == 0.0 + assert items[4] == 4.0 - items[0] = min - self.assertTrue(items[0] == min) + max_ = 3.402823e38 + min_ = -3.402823e38 - items[-4] = max - self.assertTrue(items[-4] == max) + items[0] = max_ + assert items[0] == max_ - items[-1] = min - self.assertTrue(items[-1] == min) + items[0] = min_ + assert items[0] == min_ - def test(): - object = Test.DoubleArrayTest() - v = object.items["wrong"] + items[-4] = max_ + assert items[-4] == max_ - self.assertRaises(TypeError, test) + items[-1] = min_ + assert items[-1] == min_ - def test(): - object = Test.DoubleArrayTest() - object[0] = "wrong" + with pytest.raises(TypeError): + ob = Test.SingleArrayTest() + _ = ob.items["wrong"] - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.SingleArrayTest() + ob[0] = "wrong" - def testDecimalArray(self): - """Test Decimal arrays.""" - object = Test.DecimalArrayTest() - items = object.items - from System import Decimal - max_d = Decimal.Parse("79228162514264337593543950335") - min_d = Decimal.Parse("-79228162514264337593543950335") +def test_double_array(): + """Test Double arrays.""" + ob = Test.DoubleArrayTest() + items = ob.items - self.assertTrue(len(items) == 5) + assert len(items) == 5 - self.assertTrue(items[0] == Decimal(0)) - self.assertTrue(items[4] == Decimal(4)) + assert items[0] == 0.0 + assert items[4] == 4.0 - items[0] = max_d - self.assertTrue(items[0] == max_d) + max_ = 1.7976931348623157e308 + min_ = -1.7976931348623157e308 - items[0] = min_d - self.assertTrue(items[0] == min_d) + items[0] = max_ + assert items[0] == max_ - items[-4] = max_d - self.assertTrue(items[-4] == max_d) + items[0] = min_ + assert items[0] == min_ - items[-1] = min_d - self.assertTrue(items[-1] == min_d) + items[-4] = max_ + assert items[-4] == max_ - def test(): - object = Test.DecimalArrayTest() - v = object.items["wrong"] + items[-1] = min_ + assert items[-1] == min_ - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.DoubleArrayTest() + _ = ob.items["wrong"] - def test(): - object = Test.DecimalArrayTest() - object[0] = "wrong" + with pytest.raises(TypeError): + ob = Test.DoubleArrayTest() + ob[0] = "wrong" - self.assertRaises(TypeError, test) - def testStringArray(self): - """Test String arrays.""" - object = Test.StringArrayTest() - items = object.items +def test_decimal_array(): + """Test Decimal arrays.""" + ob = Test.DecimalArrayTest() + items = ob.items - self.assertTrue(len(items) == 5) + from System import Decimal + max_d = Decimal.Parse("79228162514264337593543950335") + min_d = Decimal.Parse("-79228162514264337593543950335") - self.assertTrue(items[0] == '0') - self.assertTrue(items[4] == '4') + assert len(items) == 5 - items[0] = "spam" - self.assertTrue(items[0] == "spam") + assert items[0] == Decimal(0) + assert items[4] == Decimal(4) - items[0] = "eggs" - self.assertTrue(items[0] == "eggs") + items[0] = max_d + assert items[0] == max_d - items[-4] = "spam" - self.assertTrue(items[-4] == "spam") + items[0] = min_d + assert items[0] == min_d - items[-1] = "eggs" - self.assertTrue(items[-1] == "eggs") + items[-4] = max_d + assert items[-4] == max_d - def test(): - object = Test.StringArrayTest() - v = object.items["wrong"] + items[-1] = min_d + assert items[-1] == min_d - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.DecimalArrayTest() + _ = ob.items["wrong"] - def test(): - object = Test.Int64ArrayTest() - object[0] = 0 + with pytest.raises(TypeError): + ob = Test.DecimalArrayTest() + ob[0] = "wrong" - self.assertRaises(TypeError, test) - def testEnumArray(self): - """Test enum arrays.""" - from Python.Test import ShortEnum - object = Test.EnumArrayTest() - items = object.items +def test_string_array(): + """Test String arrays.""" + ob = Test.StringArrayTest() + items = ob.items - self.assertTrue(len(items) == 5) + assert len(items) == 5 - self.assertTrue(items[0] == ShortEnum.Zero) - self.assertTrue(items[4] == ShortEnum.Four) + assert items[0] == '0' + assert items[4] == '4' - items[0] = ShortEnum.Four - self.assertTrue(items[0] == ShortEnum.Four) + items[0] = "spam" + assert items[0] == "spam" - items[0] = ShortEnum.Zero - self.assertTrue(items[0] == ShortEnum.Zero) + items[0] = "eggs" + assert items[0] == "eggs" - items[-4] = ShortEnum.Four - self.assertTrue(items[-4] == ShortEnum.Four) + items[-4] = "spam" + assert items[-4] == "spam" - items[-1] = ShortEnum.Zero - self.assertTrue(items[-1] == ShortEnum.Zero) + items[-1] = "eggs" + assert items[-1] == "eggs" - def test(): - object = Test.EnumArrayTest() - object.items[0] = 99 + with pytest.raises(TypeError): + ob = Test.StringArrayTest() + _ = ob.items["wrong"] - self.assertRaises(ValueError, test) + with pytest.raises(TypeError): + ob = Test.Int64ArrayTest() + ob[0] = 0 - def test(): - object = Test.EnumArrayTest() - v = object.items["wrong"] - self.assertRaises(TypeError, test) +def test_enum_array(): + """Test enum arrays.""" + from Python.Test import ShortEnum + ob = Test.EnumArrayTest() + items = ob.items - def test(): - object = Test.EnumArrayTest() - object[0] = "wrong" + assert len(items) == 5 - self.assertRaises(TypeError, test) + assert items[0] == ShortEnum.Zero + assert items[4] == ShortEnum.Four - def testObjectArray(self): - """Test object arrays.""" - from Python.Test import Spam - object = Test.ObjectArrayTest() - items = object.items + items[0] = ShortEnum.Four + assert items[0] == ShortEnum.Four - self.assertTrue(len(items) == 5) + items[0] = ShortEnum.Zero + assert items[0] == ShortEnum.Zero - self.assertTrue(items[0].GetValue() == "0") - self.assertTrue(items[4].GetValue() == "4") + items[-4] = ShortEnum.Four + assert items[-4] == ShortEnum.Four - items[0] = Spam("4") - self.assertTrue(items[0].GetValue() == "4") + items[-1] = ShortEnum.Zero + assert items[-1] == ShortEnum.Zero - items[0] = Spam("0") - self.assertTrue(items[0].GetValue() == "0") + with pytest.raises(ValueError): + ob = Test.EnumArrayTest() + ob.items[0] = 99 - items[-4] = Spam("4") - self.assertTrue(items[-4].GetValue() == "4") + with pytest.raises(TypeError): + ob = Test.EnumArrayTest() + _ = ob.items["wrong"] - items[-1] = Spam("0") - self.assertTrue(items[-1].GetValue() == "0") + with pytest.raises(TypeError): + ob = Test.EnumArrayTest() + ob[0] = "wrong" - items[0] = 99 - self.assertTrue(items[0] == 99) - items[0] = None - self.assertTrue(items[0] == None) +def test_object_array(): + """Test ob arrays.""" + from Python.Test import Spam + ob = Test.ObjectArrayTest() + items = ob.items - def test(): - object = Test.ObjectArrayTest() - v = object.items["wrong"] + assert len(items) == 5 - self.assertRaises(TypeError, test) + assert items[0].GetValue() == "0" + assert items[4].GetValue() == "4" - def test(): - object = Test.ObjectArrayTest() - object.items["wrong"] = "wrong" + items[0] = Spam("4") + assert items[0].GetValue() == "4" - self.assertRaises(TypeError, test) + items[0] = Spam("0") + assert items[0].GetValue() == "0" - def testNullArray(self): - """Test null arrays.""" - object = Test.NullArrayTest() - items = object.items + items[-4] = Spam("4") + assert items[-4].GetValue() == "4" - self.assertTrue(len(items) == 5) + items[-1] = Spam("0") + assert items[-1].GetValue() == "0" - self.assertTrue(items[0] == None) - self.assertTrue(items[4] == None) + items[0] = 99 + assert items[0] == 99 - items[0] = "spam" - self.assertTrue(items[0] == "spam") + items[0] = None + assert items[0] is None - items[0] = None - self.assertTrue(items[0] == None) + with pytest.raises(TypeError): + ob = Test.ObjectArrayTest() + _ = ob.items["wrong"] - items[-4] = "spam" - self.assertTrue(items[-4] == "spam") + with pytest.raises(TypeError): + ob = Test.ObjectArrayTest() + ob.items["wrong"] = "wrong" - items[-1] = None - self.assertTrue(items[-1] == None) - empty = object.empty - self.assertTrue(len(empty) == 0) +def test_null_array(): + """Test null arrays.""" + ob = Test.NullArrayTest() + items = ob.items - def test(): - object = Test.NullArrayTest() - v = object.items["wrong"] + assert len(items) == 5 - self.assertRaises(TypeError, test) + assert items[0] is None + assert items[4] is None - def testInterfaceArray(self): - """Test interface arrays.""" - from Python.Test import Spam - object = Test.InterfaceArrayTest() - items = object.items + items[0] = "spam" + assert items[0] == "spam" - self.assertTrue(len(items) == 5) + items[0] = None + assert items[0] is None - self.assertTrue(items[0].GetValue() == "0") - self.assertTrue(items[4].GetValue() == "4") + items[-4] = "spam" + assert items[-4] == "spam" - items[0] = Spam("4") - self.assertTrue(items[0].GetValue() == "4") + items[-1] = None + assert items[-1] is None - items[0] = Spam("0") - self.assertTrue(items[0].GetValue() == "0") + empty = ob.empty + assert len(empty) == 0 - items[-4] = Spam("4") - self.assertTrue(items[-4].GetValue() == "4") + with pytest.raises(TypeError): + ob = Test.NullArrayTest() + _ = ob.items["wrong"] - items[-1] = Spam("0") - self.assertTrue(items[-1].GetValue() == "0") - items[0] = None - self.assertTrue(items[0] == None) +def test_interface_array(): + """Test interface arrays.""" + from Python.Test import Spam + ob = Test.InterfaceArrayTest() + items = ob.items - def test(): - object = Test.InterfaceArrayTest() - object.items[0] = 99 + assert len(items) == 5 - self.assertRaises(TypeError, test) + assert items[0].GetValue() == "0" + assert items[4].GetValue() == "4" - def test(): - object = Test.InterfaceArrayTest() - v = object.items["wrong"] + items[0] = Spam("4") + assert items[0].GetValue() == "4" - self.assertRaises(TypeError, test) + items[0] = Spam("0") + assert items[0].GetValue() == "0" - def test(): - object = Test.InterfaceArrayTest() - object.items["wrong"] = "wrong" + items[-4] = Spam("4") + assert items[-4].GetValue() == "4" - self.assertRaises(TypeError, test) + items[-1] = Spam("0") + assert items[-1].GetValue() == "0" - def testTypedArray(self): - """Test typed arrays.""" - from Python.Test import Spam - object = Test.TypedArrayTest() - items = object.items + items[0] = None + assert items[0] is None - self.assertTrue(len(items) == 5) + with pytest.raises(TypeError): + ob = Test.InterfaceArrayTest() + ob.items[0] = 99 - self.assertTrue(items[0].GetValue() == "0") - self.assertTrue(items[4].GetValue() == "4") + with pytest.raises(TypeError): + ob = Test.InterfaceArrayTest() + _ = ob.items["wrong"] - items[0] = Spam("4") - self.assertTrue(items[0].GetValue() == "4") + with pytest.raises(TypeError): + ob = Test.InterfaceArrayTest() + ob.items["wrong"] = "wrong" - items[0] = Spam("0") - self.assertTrue(items[0].GetValue() == "0") - items[-4] = Spam("4") - self.assertTrue(items[-4].GetValue() == "4") +def test_typed_array(): + """Test typed arrays.""" + from Python.Test import Spam + ob = Test.TypedArrayTest() + items = ob.items - items[-1] = Spam("0") - self.assertTrue(items[-1].GetValue() == "0") + assert len(items) == 5 - items[0] = None - self.assertTrue(items[0] == None) + assert items[0].GetValue() == "0" + assert items[4].GetValue() == "4" - def test(): - object = Test.TypedArrayTest() - object.items[0] = 99 + items[0] = Spam("4") + assert items[0].GetValue() == "4" - self.assertRaises(TypeError, test) + items[0] = Spam("0") + assert items[0].GetValue() == "0" - def test(): - object = Test.TypedArrayTest() - v = object.items["wrong"] + items[-4] = Spam("4") + assert items[-4].GetValue() == "4" - self.assertRaises(TypeError, test) + items[-1] = Spam("0") + assert items[-1].GetValue() == "0" - def test(): - object = Test.TypedArrayTest() - object.items["wrong"] = "wrong" + items[0] = None + assert items[0] is None - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.TypedArrayTest() + ob.items[0] = 99 - def testMultiDimensionalArray(self): - """Test multi-dimensional arrays.""" - object = Test.MultiDimensionalArrayTest() - items = object.items + with pytest.raises(TypeError): + ob = Test.TypedArrayTest() + _ = ob.items["wrong"] - self.assertTrue(len(items) == 25) + with pytest.raises(TypeError): + ob = Test.TypedArrayTest() + ob.items["wrong"] = "wrong" - self.assertTrue(items[0, 0] == 0) - self.assertTrue(items[0, 1] == 1) - self.assertTrue(items[0, 2] == 2) - self.assertTrue(items[0, 3] == 3) - self.assertTrue(items[0, 4] == 4) - self.assertTrue(items[1, 0] == 5) - self.assertTrue(items[1, 1] == 6) - self.assertTrue(items[1, 2] == 7) - self.assertTrue(items[1, 3] == 8) - self.assertTrue(items[1, 4] == 9) - self.assertTrue(items[2, 0] == 10) - self.assertTrue(items[2, 1] == 11) - self.assertTrue(items[2, 2] == 12) - self.assertTrue(items[2, 3] == 13) - self.assertTrue(items[2, 4] == 14) - self.assertTrue(items[3, 0] == 15) - self.assertTrue(items[3, 1] == 16) - self.assertTrue(items[3, 2] == 17) - self.assertTrue(items[3, 3] == 18) - self.assertTrue(items[3, 4] == 19) - self.assertTrue(items[4, 0] == 20) - self.assertTrue(items[4, 1] == 21) - self.assertTrue(items[4, 2] == 22) - self.assertTrue(items[4, 3] == 23) - self.assertTrue(items[4, 4] == 24) - max = 2147483647 - min = -2147483648 +def test_multi_dimensional_array(): + """Test multi-dimensional arrays.""" + ob = Test.MultiDimensionalArrayTest() + items = ob.items - items[0, 0] = max - self.assertTrue(items[0, 0] == max) + assert len(items) == 25 - items[0, 0] = min - self.assertTrue(items[0, 0] == min) + assert items[0, 0] == 0 + assert items[0, 1] == 1 + assert items[0, 2] == 2 + assert items[0, 3] == 3 + assert items[0, 4] == 4 + assert items[1, 0] == 5 + assert items[1, 1] == 6 + assert items[1, 2] == 7 + assert items[1, 3] == 8 + assert items[1, 4] == 9 + assert items[2, 0] == 10 + assert items[2, 1] == 11 + assert items[2, 2] == 12 + assert items[2, 3] == 13 + assert items[2, 4] == 14 + assert items[3, 0] == 15 + assert items[3, 1] == 16 + assert items[3, 2] == 17 + assert items[3, 3] == 18 + assert items[3, 4] == 19 + assert items[4, 0] == 20 + assert items[4, 1] == 21 + assert items[4, 2] == 22 + assert items[4, 3] == 23 + assert items[4, 4] == 24 - items[-4, 0] = max - self.assertTrue(items[-4, 0] == max) + max_ = 2147483647 + min_ = -2147483648 - items[-1, -1] = min - self.assertTrue(items[-1, -1] == min) + items[0, 0] = max_ + assert items[0, 0] == max_ - def test(): - object = Test.MultiDimensionalArrayTest() - object.items[0, 0] = max + 1 + items[0, 0] = min_ + assert items[0, 0] == min_ - self.assertRaises(OverflowError, test) + items[-4, 0] = max_ + assert items[-4, 0] == max_ - def test(): - object = Test.MultiDimensionalArrayTest() - object.items[0, 0] = min - 1 + items[-1, -1] = min_ + assert items[-1, -1] == min_ - self.assertRaises(OverflowError, test) + with pytest.raises(OverflowError): + ob = Test.MultiDimensionalArrayTest() + ob.items[0, 0] = max_ + 1 - def test(): - object = Test.MultiDimensionalArrayTest() - v = object.items["wrong", 0] + with pytest.raises(OverflowError): + ob = Test.MultiDimensionalArrayTest() + ob.items[0, 0] = min_ - 1 - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.MultiDimensionalArrayTest() + _ = ob.items["wrong", 0] - def test(): - object = Test.MultiDimensionalArrayTest() - object[0, 0] = "wrong" + with pytest.raises(TypeError): + ob = Test.MultiDimensionalArrayTest() + ob[0, 0] = "wrong" - self.assertRaises(TypeError, test) - - def testArrayIteration(self): - """Test array iteration.""" - items = Test.Int32ArrayTest().items - - for i in items: - self.assertTrue((i > -1) and (i < 5)) - - items = Test.NullArrayTest().items - - for i in items: - self.assertTrue(i == None) - - empty = Test.NullArrayTest().empty - - for i in empty: - raise TypeError('iteration over empty array') - - def testTupleArrayConversion(self): - """Test conversion of tuples to array arguments.""" - from Python.Test import ArrayConversionTest - from Python.Test import Spam - - items = [] - for i in range(10): - items.append(Spam(str(i))) - items = tuple(items) - - result = ArrayConversionTest.EchoRange(items) - self.assertTrue(result[0].__class__ == Spam) - self.assertTrue(len(result) == 10) - - def testTupleNestedArrayConversion(self): - """Test conversion of tuples to array-of-array arguments.""" - from Python.Test import ArrayConversionTest - from Python.Test import Spam - - items = [] - for i in range(10): - subs = [] - for n in range(10): - subs.append(Spam(str(i))) - items.append(tuple(subs)) - items = tuple(items) - - result = ArrayConversionTest.EchoRangeAA(items) - - self.assertTrue(len(result) == 10) - self.assertTrue(len(result[0]) == 10) - self.assertTrue(result[0][0].__class__ == Spam) - - def testListArrayConversion(self): - """Test conversion of lists to array arguments.""" - from Python.Test import ArrayConversionTest - from Python.Test import Spam - items = [] - for i in range(10): - items.append(Spam(str(i))) +def test_array_iteration(): + """Test array iteration.""" + items = Test.Int32ArrayTest().items - result = ArrayConversionTest.EchoRange(items) - self.assertTrue(result[0].__class__ == Spam) - self.assertTrue(len(result) == 10) + for i in items: + assert (i > -1) and (i < 5) - def testListNestedArrayConversion(self): - """Test conversion of lists to array-of-array arguments.""" - from Python.Test import ArrayConversionTest - from Python.Test import Spam + items = Test.NullArrayTest().items - items = [] - for i in range(10): - subs = [] - for n in range(10): - subs.append(Spam(str(i))) - items.append(subs) + for i in items: + assert i is None - result = ArrayConversionTest.EchoRangeAA(items) + empty = Test.NullArrayTest().empty - self.assertTrue(len(result) == 10) - self.assertTrue(len(result[0]) == 10) - self.assertTrue(result[0][0].__class__ == Spam) + for i in empty: + raise TypeError('iteration over empty array') - def testSequenceArrayConversion(self): - """Test conversion of sequence-like objects to array arguments.""" - from Python.Test import ArrayConversionTest - from Python.Test import Spam - if six.PY3: - from collections import UserList - else: - from UserList import UserList - items = UserList() - for i in range(10): - items.append(Spam(str(i))) +def test_tuple_array_conversion(): + """Test conversion of tuples to array arguments.""" + from Python.Test import ArrayConversionTest + from Python.Test import Spam - result = ArrayConversionTest.EchoRange(items) - self.assertTrue(result[0].__class__ == Spam) - self.assertTrue(len(result) == 10) + items = [] + for i in range(10): + items.append(Spam(str(i))) + items = tuple(items) - def testSequenceNestedArrayConversion(self): - """Test conversion of sequences to array-of-array arguments.""" - from Python.Test import ArrayConversionTest - from Python.Test import Spam - if six.PY3: - from collections import UserList - else: - from UserList import UserList + result = ArrayConversionTest.EchoRange(items) + assert result[0].__class__ == Spam + assert len(result) == 10 - items = UserList() - for i in range(10): - subs = UserList() - for n in range(10): - subs.append(Spam(str(i))) - items.append(subs) - - result = ArrayConversionTest.EchoRangeAA(items) - - self.assertTrue(len(result) == 10) - self.assertTrue(len(result[0]) == 10) - self.assertTrue(result[0][0].__class__ == Spam) - - def testTupleArrayConversionTypeChecking(self): - """Test error handling for tuple conversion to array arguments.""" - from Python.Test import ArrayConversionTest - from Python.Test import Spam - - # This should work, because null / None is a valid value in an - # array of reference types. - - items = [] - for i in range(10): - items.append(Spam(str(i))) - items[1] = None - items = tuple(items) - - result = ArrayConversionTest.EchoRange(items) - self.assertTrue(result[0].__class__ == Spam) - self.assertTrue(result[1] == None) - self.assertTrue(len(result) == 10) +def test_tuple_nested_array_conversion(): + """Test conversion of tuples to array-of-array arguments.""" + from Python.Test import ArrayConversionTest + from Python.Test import Spam - def test(items=items): - temp = list(items) - temp[1] = 1 + items = [] + for i in range(10): + subs = [] + for _ in range(10): + subs.append(Spam(str(i))) + items.append(tuple(subs)) + items = tuple(items) - result = ArrayConversionTest.EchoRange(tuple(temp)) + result = ArrayConversionTest.EchoRangeAA(items) - self.assertRaises(TypeError, test) + assert len(result) == 10 + assert len(result[0]) == 10 + assert result[0][0].__class__ == Spam - def test(items=items): - temp = list(items) - temp[1] = "spam" - result = ArrayConversionTest.EchoRange(tuple(temp)) +def test_list_array_conversion(): + """Test conversion of lists to array arguments.""" + from Python.Test import ArrayConversionTest + from Python.Test import Spam - self.assertRaises(TypeError, test) + items = [] + for i in range(10): + items.append(Spam(str(i))) - def testListArrayConversionTypeChecking(self): - """Test error handling for list conversion to array arguments.""" - from Python.Test import ArrayConversionTest - from Python.Test import Spam + result = ArrayConversionTest.EchoRange(items) + assert result[0].__class__ == Spam + assert len(result) == 10 - # This should work, because null / None is a valid value in an - # array of reference types. - items = [] - for i in range(10): - items.append(Spam(str(i))) - items[1] = None +def test_list_nested_array_conversion(): + """Test conversion of lists to array-of-array arguments.""" + from Python.Test import ArrayConversionTest + from Python.Test import Spam - result = ArrayConversionTest.EchoRange(items) + items = [] + for i in range(10): + subs = [] + for _ in range(10): + subs.append(Spam(str(i))) + items.append(subs) - self.assertTrue(result[0].__class__ == Spam) - self.assertTrue(result[1] == None) - self.assertTrue(len(result) == 10) + result = ArrayConversionTest.EchoRangeAA(items) - def test(items=items): - items[1] = 1 - result = ArrayConversionTest.EchoRange(items) - - self.assertRaises(TypeError, test) - - def test(items=items): - items[1] = "spam" - result = ArrayConversionTest.EchoRange(items) - - self.assertRaises(TypeError, test) - - def testSequenceArrayConversionTypeChecking(self): - """Test error handling for sequence conversion to array arguments.""" - from Python.Test import ArrayConversionTest - from Python.Test import Spam - if six.PY3: - from collections import UserList - else: - from UserList import UserList - - # This should work, because null / None is a valid value in an - # array of reference types. - - items = UserList() - for i in range(10): - items.append(Spam(str(i))) - items[1] = None + assert len(result) == 10 + assert len(result[0]) == 10 + assert result[0][0].__class__ == Spam - result = ArrayConversionTest.EchoRange(items) - self.assertTrue(result[0].__class__ == Spam) - self.assertTrue(result[1] == None) - self.assertTrue(len(result) == 10) +def test_sequence_array_conversion(): + """Test conversion of sequence-like obs to array arguments.""" + from Python.Test import ArrayConversionTest + from Python.Test import Spam - def test(items=items): - items[1] = 1 - result = ArrayConversionTest.EchoRange(items) + items = UserList() + for i in range(10): + items.append(Spam(str(i))) - self.assertRaises(TypeError, test) + result = ArrayConversionTest.EchoRange(items) + assert result[0].__class__ == Spam + assert len(result) == 10 - def test(items=items): - items[1] = "spam" - result = ArrayConversionTest.EchoRange(items) - self.assertRaises(TypeError, test) - - def testMDArrayConversion(self): - """Test passing of multi-dimensional array arguments.""" - from Python.Test import ArrayConversionTest - from Python.Test import Spam - from System import Array - - # Currently, the runtime does not support automagic conversion of - # Python sequences to true multi-dimensional arrays (though it - # does support arrays-of-arrays). This test exists mostly as an - # example of how a multi-dimensional array can be created and used - # with managed code from Python. +def test_sequence_nested_array_conversion(): + """Test conversion of sequences to array-of-array arguments.""" + from Python.Test import ArrayConversionTest + from Python.Test import Spam - items = Array.CreateInstance(Spam, 5, 5) - - for i in range(5): - for n in range(5): - items.SetValue(Spam(str((i, n))), (i, n)) - - result = ArrayConversionTest.EchoRangeMD(items) - - self.assertTrue(len(result) == 25) - self.assertTrue(result[0, 0].__class__ == Spam) - self.assertTrue(result[0, 0].__class__ == Spam) - - def testBoxedValueTypeMutationResult(self): - """Test behavior of boxed value types.""" - - # This test actually exists mostly as documentation of an important - # concern when dealing with value types. Python does not have any - # value type semantics that can be mapped to the CLR, so it is easy - # to accidentally write code like the following which is not really - # mutating value types in-place but changing boxed copies. - - from System.Drawing import Point - from System import Array - - items = Array.CreateInstance(Point, 5) - - for i in range(5): - items[i] = Point(i, i) - - for i in range(5): - # Boxed items, so settr will not change the array member. - self.assertTrue(items[i].X == i) - self.assertTrue(items[i].Y == i) - items[i].X = i + 1 - items[i].Y = i + 1 - self.assertTrue(items[i].X == i) - self.assertTrue(items[i].Y == i) - - for i in range(5): - # Demonstrates the workaround that will change the members. - self.assertTrue(items[i].X == i) - self.assertTrue(items[i].Y == i) - item = items[i] - item.X = i + 1 - item.Y = i + 1 - items[i] = item - self.assertTrue(items[i].X == i + 1) - self.assertTrue(items[i].Y == i + 1) - - def testSpecialArrayCreation(self): - """Test using the Array[] syntax for creating arrays.""" - from Python.Test import ISayHello1, InterfaceTest, ShortEnum - from System import Array - inst = InterfaceTest() - - value = Array[System.Boolean]([True, True]) - self.assertTrue(value[0] == True) - self.assertTrue(value[1] == True) - self.assertTrue(value.Length == 2) - - value = Array[bool]([True, True]) - self.assertTrue(value[0] == True) - self.assertTrue(value[1] == True) - self.assertTrue(value.Length == 2) - - value = Array[System.Byte]([0, 255]) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == 255) - self.assertTrue(value.Length == 2) - - value = Array[System.SByte]([0, 127]) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == 127) - self.assertTrue(value.Length == 2) - - value = Array[System.Char]([six.u('A'), six.u('Z')]) - self.assertTrue(value[0] == six.u('A')) - self.assertTrue(value[1] == six.u('Z')) - self.assertTrue(value.Length == 2) - - value = Array[System.Char]([0, 65535]) - self.assertTrue(value[0] == unichr(0)) - self.assertTrue(value[1] == unichr(65535)) - self.assertTrue(value.Length == 2) - - value = Array[System.Int16]([0, 32767]) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == 32767) - self.assertTrue(value.Length == 2) - - value = Array[System.Int32]([0, 2147483647]) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == 2147483647) - self.assertTrue(value.Length == 2) - - value = Array[int]([0, 2147483647]) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == 2147483647) - self.assertTrue(value.Length == 2) - - value = Array[System.Int64]([0, long(9223372036854775807)]) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == long(9223372036854775807)) - self.assertTrue(value.Length == 2) - - # there's no explicit long type in python3, use System.Int64 instead - if not six.PY3: - value = Array[long]([0, long(9223372036854775807)]) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == long(9223372036854775807)) - self.assertTrue(value.Length == 2) - - value = Array[System.UInt16]([0, 65000]) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == 65000) - self.assertTrue(value.Length == 2) - - value = Array[System.UInt32]([0, long(4294967295)]) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == long(4294967295)) - self.assertTrue(value.Length == 2) - - value = Array[System.UInt64]([0, long(18446744073709551615)]) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == long(18446744073709551615)) - self.assertTrue(value.Length == 2) - - value = Array[System.Single]([0.0, 3.402823e38]) - self.assertTrue(value[0] == 0.0) - self.assertTrue(value[1] == 3.402823e38) - self.assertTrue(value.Length == 2) - - value = Array[System.Double]([0.0, 1.7976931348623157e308]) - self.assertTrue(value[0] == 0.0) - self.assertTrue(value[1] == 1.7976931348623157e308) - self.assertTrue(value.Length == 2) - - value = Array[float]([0.0, 1.7976931348623157e308]) - self.assertTrue(value[0] == 0.0) - self.assertTrue(value[1] == 1.7976931348623157e308) - self.assertTrue(value.Length == 2) - - value = Array[System.Decimal]([System.Decimal.Zero, System.Decimal.One]) - self.assertTrue(value[0] == System.Decimal.Zero) - self.assertTrue(value[1] == System.Decimal.One) - self.assertTrue(value.Length == 2) + items = UserList() + for i in range(10): + subs = UserList() + for _ in range(10): + subs.append(Spam(str(i))) + items.append(subs) - value = Array[System.String](["one", "two"]) - self.assertTrue(value[0] == "one") - self.assertTrue(value[1] == "two") - self.assertTrue(value.Length == 2) + result = ArrayConversionTest.EchoRangeAA(items) - value = Array[str](["one", "two"]) - self.assertTrue(value[0] == "one") - self.assertTrue(value[1] == "two") - self.assertTrue(value.Length == 2) + assert len(result) == 10 + assert len(result[0]) == 10 + assert result[0][0].__class__ == Spam - value = Array[ShortEnum]([ShortEnum.Zero, ShortEnum.One]) - self.assertTrue(value[0] == ShortEnum.Zero) - self.assertTrue(value[1] == ShortEnum.One) - self.assertTrue(value.Length == 2) - value = Array[System.Object]([inst, inst]) - self.assertTrue(value[0].__class__ == inst.__class__) - self.assertTrue(value[1].__class__ == inst.__class__) - self.assertTrue(value.Length == 2) +def test_tuple_array_conversion_type_checking(): + """Test error handling for tuple conversion to array arguments.""" + from Python.Test import ArrayConversionTest + from Python.Test import Spam - value = Array[InterfaceTest]([inst, inst]) - self.assertTrue(value[0].__class__ == inst.__class__) - self.assertTrue(value[1].__class__ == inst.__class__) - self.assertTrue(value.Length == 2) + # This should work, because null / None is a valid value in an + # array of reference types. - value = Array[ISayHello1]([inst, inst]) - self.assertTrue(value[0].__class__ == inst.__class__) - self.assertTrue(value[1].__class__ == inst.__class__) - self.assertTrue(value.Length == 2) + items = [] + for i in range(10): + items.append(Spam(str(i))) + items[1] = None + items = tuple(items) - inst = System.Exception("badness") - value = Array[System.Exception]([inst, inst]) - self.assertTrue(value[0].__class__ == inst.__class__) - self.assertTrue(value[1].__class__ == inst.__class__) - self.assertTrue(value.Length == 2) + result = ArrayConversionTest.EchoRange(items) - def testArrayAbuse(self): - """Test array abuse.""" - _class = Test.PublicArrayTest - object = Test.PublicArrayTest() + assert result[0].__class__ == Spam + assert result[1] is None + assert len(result) == 10 - def test(): - del _class.__getitem__ + with pytest.raises(TypeError): + temp = list(items) + temp[1] = 1 + _ = ArrayConversionTest.EchoRange(tuple(temp)) - self.assertRaises(AttributeError, test) + with pytest.raises(TypeError): + temp = list(items) + temp[1] = "spam" + _ = ArrayConversionTest.EchoRange(tuple(temp)) - def test(): - del object.__getitem__ - self.assertRaises(AttributeError, test) +def test_list_array_conversion_type_checking(): + """Test error handling for list conversion to array arguments.""" + from Python.Test import ArrayConversionTest + from Python.Test import Spam - def test(): - del _class.__setitem__ + # This should work, because null / None is a valid value in an + # array of reference types. - self.assertRaises(AttributeError, test) + items = [] + for i in range(10): + items.append(Spam(str(i))) + items[1] = None - def test(): - del object.__setitem__ + result = ArrayConversionTest.EchoRange(items) - self.assertRaises(AttributeError, test) + assert result[0].__class__ == Spam + assert result[1] is None + assert len(result) == 10 - def test(): - Test.PublicArrayTest.__getitem__(0, 0) + with pytest.raises(TypeError): + items[1] = 1 + _ = ArrayConversionTest.EchoRange(items) - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + items[1] = "spam" + _ = ArrayConversionTest.EchoRange(items) - def test(): - Test.PublicArrayTest.__setitem__(0, 0, 0) - self.assertRaises(TypeError, test) +def test_sequence_array_conversion_type_checking(): + """Test error handling for sequence conversion to array arguments.""" + from Python.Test import ArrayConversionTest + from Python.Test import Spam - def test(): - desc = Test.PublicArrayTest.__dict__['__getitem__'] - desc(0, 0) + # This should work, because null / None is a valid value in an + # array of reference types. - self.assertRaises(TypeError, test) + items = UserList() + for i in range(10): + items.append(Spam(str(i))) + items[1] = None - def test(): - desc = Test.PublicArrayTest.__dict__['__setitem__'] - desc(0, 0, 0) + result = ArrayConversionTest.EchoRange(items) - self.assertRaises(TypeError, test) + assert result[0].__class__ == Spam + assert result[1] is None + assert len(result) == 10 + with pytest.raises(TypeError): + items[1] = 1 + _ = ArrayConversionTest.EchoRange(items) -def test_suite(): - return unittest.makeSuite(ArrayTests) + with pytest.raises(TypeError): + items[1] = "spam" + _ = ArrayConversionTest.EchoRange(items) -def main(): - unittest.TextTestRunner().run(test_suite()) +def test_md_array_conversion(): + """Test passing of multi-dimensional array arguments.""" + from Python.Test import ArrayConversionTest + from Python.Test import Spam + from System import Array + # Currently, the runtime does not support automagic conversion of + # Python sequences to true multi-dimensional arrays (though it + # does support arrays-of-arrays). This test exists mostly as an + # example of how a multi-dimensional array can be created and used + # with managed code from Python. -if __name__ == '__main__': - main() + items = Array.CreateInstance(Spam, 5, 5) + + for i in range(5): + for n in range(5): + items.SetValue(Spam(str((i, n))), (i, n)) + + result = ArrayConversionTest.EchoRangeMD(items) + + assert len(result) == 25 + assert result[0, 0].__class__ == Spam + assert result[0, 0].__class__ == Spam + + +def test_boxed_value_type_mutation_result(): + """Test behavior of boxed value types.""" + + # This test actually exists mostly as documentation of an important + # concern when dealing with value types. Python does not have any + # value type semantics that can be mapped to the CLR, so it is easy + # to accidentally write code like the following which is not really + # mutating value types in-place but changing boxed copies. + + from System.Drawing import Point + from System import Array + + items = Array.CreateInstance(Point, 5) + + for i in range(5): + items[i] = Point(i, i) + + for i in range(5): + # Boxed items, so set_attr will not change the array member. + assert items[i].X == i + assert items[i].Y == i + items[i].X = i + 1 + items[i].Y = i + 1 + assert items[i].X == i + assert items[i].Y == i + + for i in range(5): + # Demonstrates the workaround that will change the members. + assert items[i].X == i + assert items[i].Y == i + item = items[i] + item.X = i + 1 + item.Y = i + 1 + items[i] = item + assert items[i].X == i + 1 + assert items[i].Y == i + 1 + + +def test_special_array_creation(): + """Test using the Array[] syntax for creating arrays.""" + from Python.Test import ISayHello1, InterfaceTest, ShortEnum + from System import Array + inst = InterfaceTest() + + value = Array[System.Boolean]([True, True]) + assert value[0] is True + assert value[1] is True + assert value.Length == 2 + + value = Array[bool]([True, True]) + assert value[0] is True + assert value[1] is True + assert value.Length == 2 + + value = Array[System.Byte]([0, 255]) + assert value[0] == 0 + assert value[1] == 255 + assert value.Length == 2 + + value = Array[System.SByte]([0, 127]) + assert value[0] == 0 + assert value[1] == 127 + assert value.Length == 2 + + value = Array[System.Char]([u'A', u'Z']) + assert value[0] == u'A' + assert value[1] == u'Z' + assert value.Length == 2 + + value = Array[System.Char]([0, 65535]) + assert value[0] == unichr(0) + assert value[1] == unichr(65535) + assert value.Length == 2 + + value = Array[System.Int16]([0, 32767]) + assert value[0] == 0 + assert value[1] == 32767 + assert value.Length == 2 + + value = Array[System.Int32]([0, 2147483647]) + assert value[0] == 0 + assert value[1] == 2147483647 + assert value.Length == 2 + + value = Array[int]([0, 2147483647]) + assert value[0] == 0 + assert value[1] == 2147483647 + assert value.Length == 2 + + value = Array[System.Int64]([0, long(9223372036854775807)]) + assert value[0] == 0 + assert value[1] == long(9223372036854775807) + assert value.Length == 2 + + # there's no explicit long type in python3, use System.Int64 instead + if PY2: + value = Array[long]([0, long(9223372036854775807)]) + assert value[0] == 0 + assert value[1] == long(9223372036854775807) + assert value.Length == 2 + + value = Array[System.UInt16]([0, 65000]) + assert value[0] == 0 + assert value[1] == 65000 + assert value.Length == 2 + + value = Array[System.UInt32]([0, long(4294967295)]) + assert value[0] == 0 + assert value[1] == long(4294967295) + assert value.Length == 2 + + value = Array[System.UInt64]([0, long(18446744073709551615)]) + assert value[0] == 0 + assert value[1] == long(18446744073709551615) + assert value.Length == 2 + + value = Array[System.Single]([0.0, 3.402823e38]) + assert value[0] == 0.0 + assert value[1] == 3.402823e38 + assert value.Length == 2 + + value = Array[System.Double]([0.0, 1.7976931348623157e308]) + assert value[0] == 0.0 + assert value[1] == 1.7976931348623157e308 + assert value.Length == 2 + + value = Array[float]([0.0, 1.7976931348623157e308]) + assert value[0] == 0.0 + assert value[1] == 1.7976931348623157e308 + assert value.Length == 2 + + value = Array[System.Decimal]([System.Decimal.Zero, System.Decimal.One]) + assert value[0] == System.Decimal.Zero + assert value[1] == System.Decimal.One + assert value.Length == 2 + + value = Array[System.String](["one", "two"]) + assert value[0] == "one" + assert value[1] == "two" + assert value.Length == 2 + + value = Array[str](["one", "two"]) + assert value[0] == "one" + assert value[1] == "two" + assert value.Length == 2 + + value = Array[ShortEnum]([ShortEnum.Zero, ShortEnum.One]) + assert value[0] == ShortEnum.Zero + assert value[1] == ShortEnum.One + assert value.Length == 2 + + value = Array[System.Object]([inst, inst]) + assert value[0].__class__ == inst.__class__ + assert value[1].__class__ == inst.__class__ + assert value.Length == 2 + + value = Array[InterfaceTest]([inst, inst]) + assert value[0].__class__ == inst.__class__ + assert value[1].__class__ == inst.__class__ + assert value.Length == 2 + + value = Array[ISayHello1]([inst, inst]) + assert value[0].__class__ == inst.__class__ + assert value[1].__class__ == inst.__class__ + assert value.Length == 2 + + inst = System.Exception("badness") + value = Array[System.Exception]([inst, inst]) + assert value[0].__class__ == inst.__class__ + assert value[1].__class__ == inst.__class__ + assert value.Length == 2 + + +def test_array_abuse(): + """Test array abuse.""" + _class = Test.PublicArrayTest + ob = Test.PublicArrayTest() + + with pytest.raises(AttributeError): + del _class.__getitem__ + + with pytest.raises(AttributeError): + del ob.__getitem__ + + with pytest.raises(AttributeError): + del _class.__setitem__ + + with pytest.raises(AttributeError): + del ob.__setitem__ + + with pytest.raises(TypeError): + Test.PublicArrayTest.__getitem__(0, 0) + + with pytest.raises(TypeError): + Test.PublicArrayTest.__setitem__(0, 0, 0) + + with pytest.raises(TypeError): + desc = Test.PublicArrayTest.__dict__['__getitem__'] + desc(0, 0) + + with pytest.raises(TypeError): + desc = Test.PublicArrayTest.__dict__['__setitem__'] + desc(0, 0, 0) diff --git a/src/tests/test_callback.py b/src/tests/test_callback.py new file mode 100644 index 000000000..f94a9d52e --- /dev/null +++ b/src/tests/test_callback.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +"""Test that callbacks from C# into python work.""" + + +def simpleDefaultArg(arg='test'): + return arg + + +def test_default_for_null(): + """Test that C# can use null for an optional python argument""" + from Python.Test import CallbackTest + + test_instance = CallbackTest() + ret_val = test_instance.Call_simpleDefaultArg_WithNull(__name__) + python_ret_val = simpleDefaultArg(None) + assert ret_val == python_ret_val + + +def test_default_for_none(): + """Test that C# can use no argument for an optional python argument""" + from Python.Test import CallbackTest + + test_instance = CallbackTest() + ret_val = test_instance.Call_simpleDefaultArg_WithEmptyArgs(__name__) + python_ret_val = simpleDefaultArg() + assert ret_val == python_ret_val diff --git a/src/tests/test_class.py b/src/tests/test_class.py index 9e2af14da..68773508b 100644 --- a/src/tests/test_class.py +++ b/src/tests/test_class.py @@ -1,140 +1,138 @@ -import clr -import types -import unittest +# -*- coding: utf-8 -*- +# TODO: Add tests for ClassicClass, NewStyleClass? + +"""Test CLR class support.""" import Python.Test as Test import System -import six -from Python.Test import ClassTest -from System.Collections import Hashtable +import pytest + +from ._compat import DictProxyType, range + + +def test_basic_reference_type(): + """Test usage of CLR defined reference types.""" + assert System.String.Empty == "" + + +def test_basic_value_type(): + """Test usage of CLR defined value types.""" + assert System.Int32.MaxValue == 2147483647 -if six.PY3: - DictProxyType = type(object.__dict__) -else: - DictProxyType = types.DictProxyType +def test_class_standard_attrs(): + """Test standard class attributes.""" + from Python.Test import ClassTest -class ClassTests(unittest.TestCase): - """Test CLR class support.""" + assert ClassTest.__name__ == 'ClassTest' + assert ClassTest.__module__ == 'Python.Test' + assert isinstance(ClassTest.__dict__, DictProxyType) + assert len(ClassTest.__doc__) > 0 - def testBasicReferenceType(self): - """Test usage of CLR defined reference types.""" - String = System.String - self.assertEquals(String.Empty, "") - def testBasicValueType(self): - """Test usage of CLR defined value types.""" - Int32 = System.Int32 - self.assertEquals(Int32.MaxValue, 2147483647) +def test_class_docstrings(): + """Test standard class docstring generation""" + from Python.Test import ClassTest - def testClassStandardAttrs(self): - """Test standard class attributes.""" - self.assertTrue(ClassTest.__name__ == 'ClassTest') - self.assertTrue(ClassTest.__module__ == 'Python.Test') - self.assertTrue(type(ClassTest.__dict__) == DictProxyType) - self.assertTrue(len(ClassTest.__doc__) > 0) + value = 'Void .ctor()' + assert ClassTest.__doc__ == value - def testClassDocstrings(self): - """Test standard class docstring generation""" - value = 'Void .ctor()' - self.assertTrue(ClassTest.__doc__ == value) - def testClassDefaultStr(self): - """Test the default __str__ implementation for managed objects.""" - s = System.String("this is a test") - self.assertTrue(str(s) == "this is a test") +def test_class_default_str(): + """Test the default __str__ implementation for managed objects.""" + s = System.String("this is a test") + assert str(s) == "this is a test" - def testClassDefaultRepr(self): - """Test the default __repr__ implementation for managed objects.""" - s = System.String("this is a test") - self.assertTrue(repr(s).startswith(" -1) and (item < 10) + + dict_ = ClassTest.GetHashtable() - for item in list: - self.assertTrue((item > -1) and (item < 10)) + for item in dict_: + cname = item.__class__.__name__ + assert cname.endswith('DictionaryEntry') - dict = Test.ClassTest.GetHashtable() - for item in dict: - cname = item.__class__.__name__ - self.assertTrue(cname.endswith('DictionaryEntry')) +def test_ienumerator_iteration(): + """Test iteration over objects supporting IEnumerator.""" + from Python.Test import ClassTest - def testIEnumeratorIteration(self): - """Test iteration over objects supporting IEnumerator.""" - chars = Test.ClassTest.GetEnumerator() + chars = ClassTest.GetEnumerator() - for item in chars: - self.assertTrue(item in 'test string') + for item in chars: + assert item in 'test string' - def testOverrideGetItem(self): - """Test managed subclass overriding __getitem__.""" - class MyTable(Hashtable): - def __getitem__(self, key): - value = Hashtable.__getitem__(self, key) - return 'my ' + str(value) +def test_override_get_item(): + """Test managed subclass overriding __getitem__.""" + from System.Collections import Hashtable - table = MyTable() - table['one'] = 'one' - table['two'] = 'two' - table['three'] = 'three' + class MyTable(Hashtable): + def __getitem__(self, key): + value = Hashtable.__getitem__(self, key) + return 'my ' + str(value) - self.assertTrue(table['one'] == 'my one') - self.assertTrue(table['two'] == 'my two') - self.assertTrue(table['three'] == 'my three') + table = MyTable() + table['one'] = 'one' + table['two'] = 'two' + table['three'] = 'three' - self.assertTrue(table.Count == 3) + assert table['one'] == 'my one' + assert table['two'] == 'my two' + assert table['three'] == 'my three' - def testOverrideSetItem(self): - """Test managed subclass overriding __setitem__.""" + assert table.Count == 3 - class MyTable(Hashtable): - def __setitem__(self, key, value): - value = 'my ' + str(value) - Hashtable.__setitem__(self, key, value) - table = MyTable() - table['one'] = 'one' - table['two'] = 'two' - table['three'] = 'three' +def test_override_set_item(): + """Test managed subclass overriding __setitem__.""" + from System.Collections import Hashtable - self.assertTrue(table['one'] == 'my one') - self.assertTrue(table['two'] == 'my two') - self.assertTrue(table['three'] == 'my three') + class MyTable(Hashtable): + def __setitem__(self, key, value): + value = 'my ' + str(value) + Hashtable.__setitem__(self, key, value) - self.assertTrue(table.Count == 3) + table = MyTable() + table['one'] = 'one' + table['two'] = 'two' + table['three'] = 'three' - def testAddAndRemoveClassAttribute(self): - - from System import TimeSpan + assert table['one'] == 'my one' + assert table['two'] == 'my two' + assert table['three'] == 'my three' - for i in range(100): - TimeSpan.new_method = lambda self: self.TotalMinutes - ts = TimeSpan.FromHours(1) - self.assertTrue(ts.new_method() == 60) - del TimeSpan.new_method - self.assertFalse(hasattr(ts, "new_method")) + assert table.Count == 3 - def testComparisons(self): - from System import DateTimeOffset - d1 = DateTimeOffset.Parse("2016-11-14") - d2 = DateTimeOffset.Parse("2016-11-15") +def test_add_and_remove_class_attribute(): + from System import TimeSpan - self.assertEqual(d1 == d2, False) - self.assertEqual(d1 != d2, True) + for _ in range(100): + TimeSpan.new_method = lambda self_: self_.TotalMinutes + ts = TimeSpan.FromHours(1) + assert ts.new_method() == 60 + del TimeSpan.new_method + assert not hasattr(ts, "new_method") - self.assertEqual(d1 < d2, True) - self.assertEqual(d1 <= d2, True) - self.assertEqual(d1 >= d2, False) - self.assertEqual(d1 > d2, False) - self.assertEqual(d1 == d1, True) - self.assertEqual(d1 != d1, False) +def test_comparisons(): + from System import DateTimeOffset + from Python.Test import ClassTest - self.assertEqual(d1 < d1, False) - self.assertEqual(d1 <= d1, True) - self.assertEqual(d1 >= d1, True) - self.assertEqual(d1 > d1, False) + d1 = DateTimeOffset.Parse("2016-11-14") + d2 = DateTimeOffset.Parse("2016-11-15") - self.assertEqual(d2 == d1, False) - self.assertEqual(d2 != d1, True) + assert (d1 == d2) == False + assert (d1 != d2) == True - self.assertEqual(d2 < d1, False) - self.assertEqual(d2 <= d1, False) - self.assertEqual(d2 >= d1, True) - self.assertEqual(d2 > d1, True) + assert (d1 < d2) == True + assert (d1 <= d2) == True + assert (d1 >= d2) == False + assert (d1 > d2) == False - self.assertRaises(TypeError, lambda: d1 < None) - self.assertRaises(TypeError, lambda: d1 < System.Guid()) + assert (d1 == d1) == True + assert (d1 != d1) == False - # ClassTest does not implement IComparable - c1 = ClassTest() - c2 = ClassTest() - self.assertRaises(TypeError, lambda: c1 < c2) + assert (d1 < d1) == False + assert (d1 <= d1) == True + assert (d1 >= d1) == True + assert (d1 > d1) == False - def testSelfCallback(self): - """ Test calling back and forth between this and a c# baseclass.""" - class CallbackUser(Test.SelfCallbackTest): - def DoCallback(self): - self.PyCallbackWasCalled = False - self.SameReference = False - return self.Callback(self) - def PyCallback(self, self2): - self.PyCallbackWasCalled = True - self.SameReference = self == self2 - - testobj = CallbackUser() - testobj.DoCallback() - self.assertTrue(testobj.PyCallbackWasCalled) - self.assertTrue(testobj.SameReference) + assert (d2 == d1) == False + assert (d2 != d1) == True -class ClassicClass: - def kind(self): - return 'classic' + assert (d2 < d1) == False + assert (d2 <= d1) == False + assert (d2 >= d1) == True + assert (d2 > d1) == True + with pytest.raises(TypeError): + d1 < None -class NewStyleClass(object): - def kind(self): - return 'new-style' + with pytest.raises(TypeError): + d1 < System.Guid() + # ClassTest does not implement IComparable + c1 = ClassTest() + c2 = ClassTest() + with pytest.raises(TypeError): + c1 < c2 -def test_suite(): - return unittest.makeSuite(ClassTests) +def test_self_callback(): + """Test calling back and forth between this and a c# baseclass.""" -def main(): - unittest.TextTestRunner().run(test_suite()) + class CallbackUser(Test.SelfCallbackTest): + def DoCallback(self): + self.PyCallbackWasCalled = False + self.SameReference = False + return self.Callback(self) + def PyCallback(self, self2): + self.PyCallbackWasCalled = True + self.SameReference = self == self2 -if __name__ == '__main__': - main() + testobj = CallbackUser() + testobj.DoCallback() + assert testobj.PyCallbackWasCalled + assert testobj.SameReference diff --git a/src/tests/test_clrmethod.py b/src/tests/test_clrmethod.py new file mode 100644 index 000000000..a6078bece --- /dev/null +++ b/src/tests/test_clrmethod.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- + +"""Test clrmethod and clrproperty support for calling methods and getting/setting python properties from CLR.""" + +import Python.Test as Test +import System +import pytest +import clr + +class ExampleClrClass(System.Object): + __namespace__ = "PyTest" + def __init__(self): + self._x = 3 + @clr.clrmethod(int, [int]) + def test(self, x): + return x*2 + + def get_X(self): + return self._x + def set_X(self, value): + self._x = value + X = clr.clrproperty(int, get_X, set_X) + + @clr.clrproperty(int) + def Y(self): + return self._x * 2 + +def test_set_and_get_property_from_py(): + """Test setting and getting clr-accessible properties from python.""" + t = ExampleClrClass() + assert t.X == 3 + assert t.Y == 3 * 2 + t.X = 4 + assert t.X == 4 + assert t.Y == 4 * 2 + +def test_set_and_get_property_from_clr(): + """Test setting and getting clr-accessible properties from the clr.""" + t = ExampleClrClass() + assert t.GetType().GetProperty("X").GetValue(t) == 3 + assert t.GetType().GetProperty("Y").GetValue(t) == 3 * 2 + t.GetType().GetProperty("X").SetValue(t, 4) + assert t.GetType().GetProperty("X").GetValue(t) == 4 + assert t.GetType().GetProperty("Y").GetValue(t) == 4 * 2 + + +def test_set_and_get_property_from_clr_and_py(): + """Test setting and getting clr-accessible properties alternatingly from the clr and from python.""" + t = ExampleClrClass() + assert t.GetType().GetProperty("X").GetValue(t) == 3 + assert t.GetType().GetProperty("Y").GetValue(t) == 3 * 2 + assert t.X == 3 + assert t.Y == 3 * 2 + t.GetType().GetProperty("X").SetValue(t, 4) + assert t.GetType().GetProperty("X").GetValue(t) == 4 + assert t.GetType().GetProperty("Y").GetValue(t) == 4 * 2 + assert t.X == 4 + assert t.Y == 4 * 2 + t.X = 5 + assert t.GetType().GetProperty("X").GetValue(t) == 5 + assert t.GetType().GetProperty("Y").GetValue(t) == 5 * 2 + assert t.X == 5 + assert t.Y == 5 * 2 + +def test_method_invocation_from_py(): + """Test calling a clr-accessible method from python.""" + t = ExampleClrClass() + assert t.test(41) == 41*2 + +def test_method_invocation_from_clr(): + """Test calling a clr-accessible method from the clr.""" + t = ExampleClrClass() + assert t.GetType().GetMethod("test").Invoke(t, [37]) == 37*2 diff --git a/src/tests/test_compat.py b/src/tests/test_compat.py index 8c74b855a..81e7f8143 100644 --- a/src/tests/test_compat.py +++ b/src/tests/test_compat.py @@ -1,275 +1,243 @@ -import sys, os, string, unittest, types -import six +# -*- coding: utf-8 -*- +# TODO: Complete removal of methods below. Similar to test_module -if six.PY3: - ClassType = type -else: - ClassType = types.ClassType +"""Backward-compatibility tests for deprecated features.""" +import types -class CompatibilityTests(unittest.TestCase): - """ - Backward-compatibility tests for deprecated features. - """ +import pytest - def isCLRModule(self, object): - return type(object).__name__ == 'ModuleObject' +from ._compat import ClassType, PY2, PY3, range +from .utils import is_clr_class, is_clr_module, is_clr_root_module - def isCLRRootModule(self, object): - if six.PY3: - # in Python 3 the clr module is a normal python module - return object.__name__ == "clr" - return type(object).__name__ == 'CLRModule' - def isCLRClass(self, object): - return type(object).__name__ == 'CLR Metatype' # for now +# Tests for old-style CLR-prefixed module naming. +def test_simple_import(): + """Test simple import.""" + import CLR + assert is_clr_root_module(CLR) + assert CLR.__name__ == 'clr' - # Tests for old-style CLR-prefixed module naming. + import sys + assert isinstance(sys, types.ModuleType) + assert sys.__name__ == 'sys' + + if PY3: + import http.client + assert isinstance(http.client, types.ModuleType) + assert http.client.__name__ == 'http.client' + + elif PY2: + import httplib + assert isinstance(httplib, types.ModuleType) + assert httplib.__name__ == 'httplib' + + +def test_simple_import_with_alias(): + """Test simple import with aliasing.""" + import CLR as myCLR + assert is_clr_root_module(myCLR) + assert myCLR.__name__ == 'clr' + + import sys as mySys + assert isinstance(mySys, types.ModuleType) + assert mySys.__name__ == 'sys' + + if PY3: + import http.client as myHttplib + assert isinstance(myHttplib, types.ModuleType) + assert myHttplib.__name__ == 'http.client' + + elif PY2: + import httplib as myHttplib + assert isinstance(myHttplib, types.ModuleType) + assert myHttplib.__name__ == 'httplib' + + +def test_dotted_name_import(): + """Test dotted-name import.""" + import CLR.System + assert is_clr_module(CLR.System) + assert CLR.System.__name__ == 'System' + + import System + assert is_clr_module(System) + assert System.__name__ == 'System' + + assert System is CLR.System + + import xml.dom + assert isinstance(xml.dom, types.ModuleType) + assert xml.dom.__name__ == 'xml.dom' + + +def test_dotted_name_import_with_alias(): + """Test dotted-name import with aliasing.""" + import CLR.System as myCLRSystem + assert is_clr_module(myCLRSystem) + assert myCLRSystem.__name__ == 'System' + + import System as mySystem + assert is_clr_module(mySystem) + assert mySystem.__name__ == 'System' + + assert mySystem is myCLRSystem + + import xml.dom as myDom + assert isinstance(myDom, types.ModuleType) + assert myDom.__name__ == 'xml.dom' + + +def test_simple_import_from(): + """Test simple 'import from'.""" + from CLR import System + assert is_clr_module(System) + assert System.__name__ == 'System' + + from xml import dom + assert isinstance(dom, types.ModuleType) + assert dom.__name__ == 'xml.dom' - def testSimpleImport(self): - """Test simple import.""" - import CLR - self.assertTrue(self.isCLRRootModule(CLR)) - self.assertTrue(CLR.__name__ == 'clr') - - import sys - self.assertTrue(type(sys) == types.ModuleType) - self.assertTrue(sys.__name__ == 'sys') - - if six.PY3: - import http.client - self.assertTrue(type(http.client) == types.ModuleType) - self.assertTrue(http.client.__name__ == 'http.client') - - else: - import httplib - self.assertTrue(type(httplib) == types.ModuleType) - self.assertTrue(httplib.__name__ == 'httplib') - - def testSimpleImportWithAlias(self): - """Test simple import with aliasing.""" - import CLR as myCLR - self.assertTrue(self.isCLRRootModule(myCLR)) - self.assertTrue(myCLR.__name__ == 'clr') - - import sys as mySys - self.assertTrue(type(mySys) == types.ModuleType) - self.assertTrue(mySys.__name__ == 'sys') - - if six.PY3: - import http.client as myHttplib - self.assertTrue(type(myHttplib) == types.ModuleType) - self.assertTrue(myHttplib.__name__ == 'http.client') - - else: - import httplib as myHttplib - self.assertTrue(type(myHttplib) == types.ModuleType) - self.assertTrue(myHttplib.__name__ == 'httplib') - - def testDottedNameImport(self): - """Test dotted-name import.""" - import CLR.System - self.assertTrue(self.isCLRModule(CLR.System)) - self.assertTrue(CLR.System.__name__ == 'System') - - import System - self.assertTrue(self.isCLRModule(System)) - self.assertTrue(System.__name__ == 'System') - - self.assertTrue(System is CLR.System) - - import xml.dom - self.assertTrue(type(xml.dom) == types.ModuleType) - self.assertTrue(xml.dom.__name__ == 'xml.dom') - - def testDottedNameImportWithAlias(self): - """Test dotted-name import with aliasing.""" - import CLR.System as myCLRSystem - self.assertTrue(self.isCLRModule(myCLRSystem)) - self.assertTrue(myCLRSystem.__name__ == 'System') - - import System as mySystem - self.assertTrue(self.isCLRModule(mySystem)) - self.assertTrue(mySystem.__name__ == 'System') - - self.assertTrue(mySystem is myCLRSystem) - - import xml.dom as myDom - self.assertTrue(type(myDom) == types.ModuleType) - self.assertTrue(myDom.__name__ == 'xml.dom') - - def testSimpleImportFrom(self): - """Test simple 'import from'.""" - from CLR import System - self.assertTrue(self.isCLRModule(System)) - self.assertTrue(System.__name__ == 'System') - - from xml import dom - self.assertTrue(type(dom) == types.ModuleType) - self.assertTrue(dom.__name__ == 'xml.dom') - - def testSimpleImportFromWithAlias(self): - """Test simple 'import from' with aliasing.""" - from CLR import System as mySystem - self.assertTrue(self.isCLRModule(mySystem)) - self.assertTrue(mySystem.__name__ == 'System') - - from xml import dom as myDom - self.assertTrue(type(myDom) == types.ModuleType) - self.assertTrue(myDom.__name__ == 'xml.dom') - - def testDottedNameImportFrom(self): - """Test dotted-name 'import from'.""" - from CLR.System import Xml - self.assertTrue(self.isCLRModule(Xml)) - self.assertTrue(Xml.__name__ == 'System.Xml') - - from CLR.System.Xml import XmlDocument - self.assertTrue(self.isCLRClass(XmlDocument)) - self.assertTrue(XmlDocument.__name__ == 'XmlDocument') - - from xml.dom import pulldom - self.assertTrue(type(pulldom) == types.ModuleType) - self.assertTrue(pulldom.__name__ == 'xml.dom.pulldom') - - from xml.dom.pulldom import PullDOM - self.assertTrue(type(PullDOM) == ClassType) - self.assertTrue(PullDOM.__name__ == 'PullDOM') - - def testDottedNameImportFromWithAlias(self): - """Test dotted-name 'import from' with aliasing.""" - from CLR.System import Xml as myXml - self.assertTrue(self.isCLRModule(myXml)) - self.assertTrue(myXml.__name__ == 'System.Xml') - - from CLR.System.Xml import XmlDocument as myXmlDocument - self.assertTrue(self.isCLRClass(myXmlDocument)) - self.assertTrue(myXmlDocument.__name__ == 'XmlDocument') - - from xml.dom import pulldom as myPulldom - self.assertTrue(type(myPulldom) == types.ModuleType) - self.assertTrue(myPulldom.__name__ == 'xml.dom.pulldom') - - from xml.dom.pulldom import PullDOM as myPullDOM - self.assertTrue(type(myPullDOM) == ClassType) - self.assertTrue(myPullDOM.__name__ == 'PullDOM') - - def testFromModuleImportStar(self): - """Test from module import * behavior.""" - import clr - clr.AddReference("System.Management") - - count = len(locals().keys()) - m = __import__('CLR.System.Management', globals(), locals(), ['*']) - self.assertTrue(m.__name__ == 'System.Management') - self.assertTrue(self.isCLRModule(m)) - self.assertTrue(len(locals().keys()) > count + 1) - - m2 = __import__('System.Management', globals(), locals(), ['*']) - self.assertTrue(m2.__name__ == 'System.Management') - self.assertTrue(self.isCLRModule(m2)) - self.assertTrue(len(locals().keys()) > count + 1) - - self.assertTrue(m is m2) - - def testExplicitAssemblyLoad(self): - """Test explicit assembly loading using standard CLR tools.""" - from CLR.System.Reflection import Assembly - from CLR import System - import sys - - assembly = Assembly.LoadWithPartialName('System.Data') - self.assertTrue(assembly != None) - - import CLR.System.Data - self.assertTrue('System.Data' in sys.modules) - - assembly = Assembly.LoadWithPartialName('SpamSpamSpamSpamEggsAndSpam') - self.assertTrue(assembly == None) - - def testImplicitLoadAlreadyValidNamespace(self): - """Test implicit assembly load over an already valid namespace.""" - # In this case, the mscorlib assembly (loaded by default) defines - # a number of types in the System namespace. There is also a System - # assembly, which is _not_ loaded by default, which also contains - # types in the System namespace. The desired behavior is for the - # Python runtime to "do the right thing", allowing types from both - # assemblies to be found in the CLR.System module implicitly. - import CLR.System - self.assertTrue(self.isCLRClass(CLR.System.UriBuilder)) - - def testImportNonExistantModule(self): - """Test import failure for a non-existant module.""" - - def test(): - import System.SpamSpamSpam - - def testclr(): - import CLR.System.SpamSpamSpam - - self.assertRaises(ImportError, test) - self.assertRaises(ImportError, testclr) - - def testLookupNoNamespaceType(self): - """Test lookup of types without a qualified namespace.""" - import CLR.Python.Test - import CLR - self.assertTrue(self.isCLRClass(CLR.NoNamespaceType)) - def testModuleLookupRecursion(self): - """Test for recursive lookup handling.""" +def test_simple_import_from_with_alias(): + """Test simple 'import from' with aliasing.""" + from CLR import System as mySystem + assert is_clr_module(mySystem) + assert mySystem.__name__ == 'System' - def test1(): - from CLR import CLR + from xml import dom as myDom + assert isinstance(myDom, types.ModuleType) + assert myDom.__name__ == 'xml.dom' - self.assertRaises(ImportError, test1) - def test2(): - import CLR - x = CLR.CLR +def test_dotted_name_import_from(): + """Test dotted-name 'import from'.""" + from CLR.System import Xml + assert is_clr_module(Xml) + assert Xml.__name__ == 'System.Xml' - self.assertRaises(AttributeError, test2) + from CLR.System.Xml import XmlDocument + assert is_clr_class(XmlDocument) + assert XmlDocument.__name__ == 'XmlDocument' - def testModuleGetAttr(self): - """Test module getattr behavior.""" - import CLR.System as System + from xml.dom import pulldom + assert isinstance(pulldom, types.ModuleType) + assert pulldom.__name__ == 'xml.dom.pulldom' - int_type = System.Int32 - self.assertTrue(self.isCLRClass(int_type)) + from xml.dom.pulldom import PullDOM + assert isinstance(PullDOM, ClassType) + assert PullDOM.__name__ == 'PullDOM' - module = System.Xml - self.assertTrue(self.isCLRModule(module)) - def test(): - spam = System.Spam +def test_dotted_name_import_from_with_alias(): + """Test dotted-name 'import from' with aliasing.""" + from CLR.System import Xml as myXml + assert is_clr_module(myXml) + assert myXml.__name__ == 'System.Xml' - self.assertRaises(AttributeError, test) + from CLR.System.Xml import XmlDocument as myXmlDocument + assert is_clr_class(myXmlDocument) + assert myXmlDocument.__name__ == 'XmlDocument' - def test(): - spam = getattr(System, 1) + from xml.dom import pulldom as myPulldom + assert isinstance(myPulldom, types.ModuleType) + assert myPulldom.__name__ == 'xml.dom.pulldom' - self.assertRaises(TypeError, test) + from xml.dom.pulldom import PullDOM as myPullDOM + assert isinstance(myPullDOM, ClassType) + assert myPullDOM.__name__ == 'PullDOM' - def test000MultipleImports(self): - # import CLR did raise a Seg Fault once - # test if the Exceptions.warn() method still causes it - for n in range(100): - import CLR +def test_from_module_import_star(): + """Test from module import * behavior.""" + count = len(locals().keys()) + m = __import__('CLR.System.Management', globals(), locals(), ['*']) + assert m.__name__ == 'System.Management' + assert is_clr_module(m) + assert len(locals().keys()) > count + 1 -def test_suite(): - return unittest.makeSuite(CompatibilityTests) + m2 = __import__('System.Management', globals(), locals(), ['*']) + assert m2.__name__ == 'System.Management' + assert is_clr_module(m2) + assert len(locals().keys()) > count + 1 + assert m is m2 -def main(): - unittest.TextTestRunner().run(test_suite()) +def test_explicit_assembly_load(): + """Test explicit assembly loading using standard CLR tools.""" + from CLR.System.Reflection import Assembly + from CLR import System + import sys -if __name__ == '__main__': - try: - import System - except ImportError: - print("Load clr import hook") - import clr + assembly = Assembly.LoadWithPartialName('System.Data') + assert assembly is not None - main() + import CLR.System.Data + assert 'System.Data' in sys.modules + + assembly = Assembly.LoadWithPartialName('SpamSpamSpamSpamEggsAndSpam') + assert assembly is None + + +def test_implicit_load_already_valid_namespace(): + """Test implicit assembly load over an already valid namespace.""" + # In this case, the mscorlib assembly (loaded by default) defines + # a number of types in the System namespace. There is also a System + # assembly, which is _not_ loaded by default, which also contains + # types in the System namespace. The desired behavior is for the + # Python runtime to "do the right thing", allowing types from both + # assemblies to be found in the CLR.System module implicitly. + import CLR.System + assert is_clr_class(CLR.System.UriBuilder) + + +def test_import_non_existant_module(): + """Test import failure for a non-existent module.""" + with pytest.raises(ImportError): + import System.SpamSpamSpam + + with pytest.raises(ImportError): + import CLR.System.SpamSpamSpam + + +def test_lookup_no_namespace_type(): + """Test lookup of types without a qualified namespace.""" + import CLR.Python.Test + import CLR + assert is_clr_class(CLR.NoNamespaceType) + + +def test_module_lookup_recursion(): + """Test for recursive lookup handling.""" + with pytest.raises(ImportError): + from CLR import CLR + + with pytest.raises(AttributeError): + import CLR + _ = CLR.CLR + + +def test_module_get_attr(): + """Test module getattr behavior.""" + import CLR.System as System + + int_type = System.Int32 + assert is_clr_class(int_type) + + module = System.Xml + assert is_clr_module(module) + + with pytest.raises(AttributeError): + _ = System.Spam + + with pytest.raises(TypeError): + _ = getattr(System, 1) + + +def test_multiple_imports(): + # import CLR did raise a Seg Fault once + # test if the Exceptions.warn() method still causes it + for _ in range(100): + import CLR + _ = CLR diff --git a/src/tests/test_constructors.py b/src/tests/test_constructors.py index 6e02528bb..5e5489630 100644 --- a/src/tests/test_constructors.py +++ b/src/tests/test_constructors.py @@ -1,59 +1,46 @@ -import sys, os, string, unittest, types -import clr +# -*- coding: utf-8 -*- -clr.AddReference("Python.Test") -import Python.Test as Test -import System - - -class ConstructorTests(unittest.TestCase): - """Test CLR class constructor support.""" +"""Test CLR class constructor support.""" - def testEnumConstructor(self): - """Test enum constructor args""" - from System import TypeCode - from Python.Test import EnumConstructorTest - - ob = EnumConstructorTest(TypeCode.Int32) - self.assertTrue(ob.value == TypeCode.Int32) +import System - def testFlagsConstructor(self): - """Test flags constructor args""" - from Python.Test import FlagsConstructorTest - from System.IO import FileAccess - flags = FileAccess.Read | FileAccess.Write - ob = FlagsConstructorTest(flags) - self.assertTrue(ob.value == flags) +def test_enum_constructor(): + """Test enum constructor args""" + from System import TypeCode + from Python.Test import EnumConstructorTest - def testStructConstructor(self): - """Test struct constructor args""" - from System import Guid - from Python.Test import StructConstructorTest + ob = EnumConstructorTest(TypeCode.Int32) + assert ob.value == TypeCode.Int32 - guid = Guid.NewGuid() - ob = StructConstructorTest(guid) - self.assertTrue(ob.value == guid) - def testSubclassConstructor(self): - """Test subclass constructor args""" - from Python.Test import SubclassConstructorTest +def test_flags_constructor(): + """Test flags constructor args""" + from Python.Test import FlagsConstructorTest + from System.IO import FileAccess - class sub(System.Exception): - pass + flags = FileAccess.Read | FileAccess.Write + ob = FlagsConstructorTest(flags) + assert ob.value == flags - instance = sub() - ob = SubclassConstructorTest(instance) - self.assertTrue(isinstance(ob.value, System.Exception)) +def test_struct_constructor(): + """Test struct constructor args""" + from System import Guid + from Python.Test import StructConstructorTest -def test_suite(): - return unittest.makeSuite(ConstructorTests) + guid = Guid.NewGuid() + ob = StructConstructorTest(guid) + assert ob.value == guid -def main(): - unittest.TextTestRunner().run(test_suite()) +def test_subclass_constructor(): + """Test subclass constructor args""" + from Python.Test import SubclassConstructorTest + class Sub(System.Exception): + pass -if __name__ == '__main__': - main() + instance = Sub() + ob = SubclassConstructorTest(instance) + assert isinstance(ob.value, System.Exception) diff --git a/src/tests/test_conversion.py b/src/tests/test_conversion.py index a00a91c48..53e5d8051 100644 --- a/src/tests/test_conversion.py +++ b/src/tests/test_conversion.py @@ -1,844 +1,694 @@ -import sys, os, string, unittest, types -from Python.Test import ConversionTest -import System -import six - -if six.PY3: - long = int - unichr = chr - - -class ConversionTests(unittest.TestCase): - """Test CLR <-> Python type conversions.""" - - def testBoolConversion(self): - """Test bool conversion.""" - object = ConversionTest() - self.assertTrue(object.BooleanField == False) - self.assertTrue(object.BooleanField is False) - self.assertTrue(object.BooleanField == 0) - - object.BooleanField = True - self.assertTrue(object.BooleanField == True) - self.assertTrue(object.BooleanField is True) - self.assertTrue(object.BooleanField == 1) - - object.BooleanField = False - self.assertTrue(object.BooleanField == False) - self.assertTrue(object.BooleanField is False) - self.assertTrue(object.BooleanField == 0) - - object.BooleanField = 1 - self.assertTrue(object.BooleanField == True) - self.assertTrue(object.BooleanField is True) - self.assertTrue(object.BooleanField == 1) - - object.BooleanField = 0 - self.assertTrue(object.BooleanField == False) - self.assertTrue(object.BooleanField is False) - self.assertTrue(object.BooleanField == 0) - - object.BooleanField = System.Boolean(None) - self.assertTrue(object.BooleanField == False) - self.assertTrue(object.BooleanField is False) - self.assertTrue(object.BooleanField == 0) - - object.BooleanField = System.Boolean('') - self.assertTrue(object.BooleanField == False) - self.assertTrue(object.BooleanField is False) - self.assertTrue(object.BooleanField == 0) - - object.BooleanField = System.Boolean(0) - self.assertTrue(object.BooleanField == False) - self.assertTrue(object.BooleanField is False) - self.assertTrue(object.BooleanField == 0) - - object.BooleanField = System.Boolean(1) - self.assertTrue(object.BooleanField == True) - self.assertTrue(object.BooleanField is True) - self.assertTrue(object.BooleanField == 1) - - object.BooleanField = System.Boolean('a') - self.assertTrue(object.BooleanField == True) - self.assertTrue(object.BooleanField is True) - self.assertTrue(object.BooleanField == 1) - - def testSByteConversion(self): - """Test sbyte conversion.""" - self.assertTrue(System.SByte.MaxValue == 127) - self.assertTrue(System.SByte.MinValue == -128) - - object = ConversionTest() - self.assertTrue(object.SByteField == 0) - - object.SByteField = 127 - self.assertTrue(object.SByteField == 127) - - object.SByteField = -128 - self.assertTrue(object.SByteField == -128) - - object.SByteField = System.SByte(127) - self.assertTrue(object.SByteField == 127) - - object.SByteField = System.SByte(-128) - self.assertTrue(object.SByteField == -128) - - def test(): - ConversionTest().SByteField = "spam" - - self.assertRaises(TypeError, test) - - def test(): - ConversionTest().SByteField = None - - self.assertRaises(TypeError, test) - - def test(): - ConversionTest().SByteField = 128 - - self.assertRaises(OverflowError, test) - - def test(): - ConversionTest().SByteField = -129 - - self.assertRaises(OverflowError, test) - - def test(): - value = System.SByte(128) - - self.assertRaises(OverflowError, test) - - def test(): - value = System.SByte(-129) - - self.assertRaises(OverflowError, test) - - def testByteConversion(self): - """Test byte conversion.""" - self.assertTrue(System.Byte.MaxValue == 255) - self.assertTrue(System.Byte.MinValue == 0) +# -*- coding: utf-8 -*- - object = ConversionTest() - self.assertTrue(object.ByteField == 0) +"""Test CLR <-> Python type conversions.""" - object.ByteField = 255 - self.assertTrue(object.ByteField == 255) - - object.ByteField = 0 - self.assertTrue(object.ByteField == 0) - - object.ByteField = System.Byte(255) - self.assertTrue(object.ByteField == 255) - - object.ByteField = System.Byte(0) - self.assertTrue(object.ByteField == 0) - - def test(): - ConversionTest().ByteField = "spam" - - self.assertRaises(TypeError, test) - - def test(): - ConversionTest().ByteField = None - - self.assertRaises(TypeError, test) - - def test(): - ConversionTest().ByteField = 256 - - self.assertRaises(OverflowError, test) - - def test(): - ConversionTest().ByteField = -1 - - self.assertRaises(OverflowError, test) - - def test(): - value = System.Byte(256) - - self.assertRaises(OverflowError, test) - - def test(): - value = System.Byte(-1) - - self.assertRaises(OverflowError, test) - - def testCharConversion(self): - """Test char conversion.""" - self.assertTrue(System.Char.MaxValue == unichr(65535)) - self.assertTrue(System.Char.MinValue == unichr(0)) - - object = ConversionTest() - self.assertTrue(object.CharField == six.u('A')) - - object.CharField = 'B' - self.assertTrue(object.CharField == six.u('B')) - - object.CharField = six.u('B') - self.assertTrue(object.CharField == six.u('B')) - - object.CharField = 67 - self.assertTrue(object.CharField == six.u('C')) - - def test(): - ConversionTest().CharField = 65536 - - self.assertRaises(OverflowError, test) - - def test(): - ConversionTest().CharField = -1 - - self.assertRaises(OverflowError, test) - - def test(): - ConversionTest().CharField = None - - self.assertRaises(TypeError, test) - - def testInt16Conversion(self): - """Test int16 conversion.""" - self.assertTrue(System.Int16.MaxValue == 32767) - self.assertTrue(System.Int16.MinValue == -32768) - - object = ConversionTest() - self.assertTrue(object.Int16Field == 0) - - object.Int16Field = 32767 - self.assertTrue(object.Int16Field == 32767) - - object.Int16Field = -32768 - self.assertTrue(object.Int16Field == -32768) - - object.Int16Field = System.Int16(32767) - self.assertTrue(object.Int16Field == 32767) - - object.Int16Field = System.Int16(-32768) - self.assertTrue(object.Int16Field == -32768) +import System +import pytest +from Python.Test import ConversionTest - def test(): - ConversionTest().Int16Field = "spam" +from ._compat import indexbytes, long, unichr - self.assertRaises(TypeError, test) - def test(): - ConversionTest().Int16Field = None +def test_bool_conversion(): + """Test bool conversion.""" + ob = ConversionTest() + assert ob.BooleanField is False + assert ob.BooleanField is False + assert ob.BooleanField == 0 - self.assertRaises(TypeError, test) + ob.BooleanField = True + assert ob.BooleanField is True + assert ob.BooleanField is True + assert ob.BooleanField == 1 - def test(): - ConversionTest().Int16Field = 32768 + ob.BooleanField = False + assert ob.BooleanField is False + assert ob.BooleanField is False + assert ob.BooleanField == 0 - self.assertRaises(OverflowError, test) + ob.BooleanField = 1 + assert ob.BooleanField is True + assert ob.BooleanField is True + assert ob.BooleanField == 1 - def test(): - ConversionTest().Int16Field = -32769 + ob.BooleanField = 0 + assert ob.BooleanField is False + assert ob.BooleanField is False + assert ob.BooleanField == 0 - self.assertRaises(OverflowError, test) + ob.BooleanField = System.Boolean(None) + assert ob.BooleanField is False + assert ob.BooleanField is False + assert ob.BooleanField == 0 - def test(): - value = System.Int16(32768) + ob.BooleanField = System.Boolean('') + assert ob.BooleanField is False + assert ob.BooleanField is False + assert ob.BooleanField == 0 - self.assertRaises(OverflowError, test) + ob.BooleanField = System.Boolean(0) + assert ob.BooleanField is False + assert ob.BooleanField is False + assert ob.BooleanField == 0 - def test(): - value = System.Int16(-32769) + ob.BooleanField = System.Boolean(1) + assert ob.BooleanField is True + assert ob.BooleanField is True + assert ob.BooleanField == 1 - self.assertRaises(OverflowError, test) + ob.BooleanField = System.Boolean('a') + assert ob.BooleanField is True + assert ob.BooleanField is True + assert ob.BooleanField == 1 - def testInt32Conversion(self): - """Test int32 conversion.""" - self.assertTrue(System.Int32.MaxValue == 2147483647) - self.assertTrue(System.Int32.MinValue == -2147483648) - object = ConversionTest() - self.assertTrue(object.Int32Field == 0) +def test_sbyte_conversion(): + """Test sbyte conversion.""" + assert System.SByte.MaxValue == 127 + assert System.SByte.MinValue == -128 - object.Int32Field = 2147483647 - self.assertTrue(object.Int32Field == 2147483647) + ob = ConversionTest() + assert ob.SByteField == 0 - object.Int32Field = -2147483648 - self.assertTrue(object.Int32Field == -2147483648) + ob.SByteField = 127 + assert ob.SByteField == 127 - object.Int32Field = System.Int32(2147483647) - self.assertTrue(object.Int32Field == 2147483647) + ob.SByteField = -128 + assert ob.SByteField == -128 - object.Int32Field = System.Int32(-2147483648) - self.assertTrue(object.Int32Field == -2147483648) + ob.SByteField = System.SByte(127) + assert ob.SByteField == 127 - def test(): - ConversionTest().Int32Field = "spam" + ob.SByteField = System.SByte(-128) + assert ob.SByteField == -128 - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ConversionTest().SByteField = "spam" - def test(): - ConversionTest().Int32Field = None + with pytest.raises(TypeError): + ConversionTest().SByteField = None - self.assertRaises(TypeError, test) + with pytest.raises(OverflowError): + ConversionTest().SByteField = 128 - def test(): - ConversionTest().Int32Field = 2147483648 + with pytest.raises(OverflowError): + ConversionTest().SByteField = -129 - self.assertRaises(OverflowError, test) + with pytest.raises(OverflowError): + _ = System.SByte(128) - def test(): - ConversionTest().Int32Field = -2147483649 + with pytest.raises(OverflowError): + _ = System.SByte(-129) - self.assertRaises(OverflowError, test) - def test(): - value = System.Int32(2147483648) +def test_byte_conversion(): + """Test byte conversion.""" + assert System.Byte.MaxValue == 255 + assert System.Byte.MinValue == 0 - self.assertRaises(OverflowError, test) + ob = ConversionTest() + assert ob.ByteField == 0 - def test(): - value = System.Int32(-2147483649) + ob.ByteField = 255 + assert ob.ByteField == 255 - self.assertRaises(OverflowError, test) + ob.ByteField = 0 + assert ob.ByteField == 0 - def testInt64Conversion(self): - """Test int64 conversion.""" - self.assertTrue(System.Int64.MaxValue == long(9223372036854775807)) - self.assertTrue(System.Int64.MinValue == long(-9223372036854775808)) + ob.ByteField = System.Byte(255) + assert ob.ByteField == 255 - object = ConversionTest() - self.assertTrue(object.Int64Field == 0) + ob.ByteField = System.Byte(0) + assert ob.ByteField == 0 - object.Int64Field = long(9223372036854775807) - self.assertTrue(object.Int64Field == long(9223372036854775807)) + with pytest.raises(TypeError): + ConversionTest().ByteField = "spam" - object.Int64Field = long(-9223372036854775808) - self.assertTrue(object.Int64Field == long(-9223372036854775808)) + with pytest.raises(TypeError): + ConversionTest().ByteField = None - object.Int64Field = System.Int64(long(9223372036854775807)) - self.assertTrue(object.Int64Field == long(9223372036854775807)) + with pytest.raises(OverflowError): + ConversionTest().ByteField = 256 - object.Int64Field = System.Int64(long(-9223372036854775808)) - self.assertTrue(object.Int64Field == long(-9223372036854775808)) + with pytest.raises(OverflowError): + ConversionTest().ByteField = -1 - def test(): - ConversionTest().Int64Field = "spam" + with pytest.raises(OverflowError): + _ = System.Byte(256) - self.assertRaises(TypeError, test) + with pytest.raises(OverflowError): + _ = System.Byte(-1) - def test(): - ConversionTest().Int64Field = None - self.assertRaises(TypeError, test) +def test_char_conversion(): + """Test char conversion.""" + assert System.Char.MaxValue == unichr(65535) + assert System.Char.MinValue == unichr(0) - def test(): - ConversionTest().Int64Field = long(9223372036854775808) + ob = ConversionTest() + assert ob.CharField == u'A' - self.assertRaises(OverflowError, test) + ob.CharField = 'B' + assert ob.CharField == u'B' - def test(): - ConversionTest().Int64Field = long(-9223372036854775809) + ob.CharField = u'B' + assert ob.CharField == u'B' - self.assertRaises(OverflowError, test) + ob.CharField = 67 + assert ob.CharField == u'C' - def test(): - value = System.Int64(long(9223372036854775808)) + with pytest.raises(OverflowError): + ConversionTest().CharField = 65536 - self.assertRaises(OverflowError, test) + with pytest.raises(OverflowError): + ConversionTest().CharField = -1 - def test(): - value = System.Int64(long(-9223372036854775809)) + with pytest.raises(TypeError): + ConversionTest().CharField = None - self.assertRaises(OverflowError, test) - def testUInt16Conversion(self): - """Test uint16 conversion.""" - self.assertTrue(System.UInt16.MaxValue == 65535) - self.assertTrue(System.UInt16.MinValue == 0) +def test_int16_conversion(): + """Test int16 conversion.""" + assert System.Int16.MaxValue == 32767 + assert System.Int16.MinValue == -32768 - object = ConversionTest() - self.assertTrue(object.UInt16Field == 0) + ob = ConversionTest() + assert ob.Int16Field == 0 - object.UInt16Field = 65535 - self.assertTrue(object.UInt16Field == 65535) + ob.Int16Field = 32767 + assert ob.Int16Field == 32767 - object.UInt16Field = -0 - self.assertTrue(object.UInt16Field == 0) + ob.Int16Field = -32768 + assert ob.Int16Field == -32768 - object.UInt16Field = System.UInt16(65535) - self.assertTrue(object.UInt16Field == 65535) + ob.Int16Field = System.Int16(32767) + assert ob.Int16Field == 32767 - object.UInt16Field = System.UInt16(0) - self.assertTrue(object.UInt16Field == 0) + ob.Int16Field = System.Int16(-32768) + assert ob.Int16Field == -32768 - def test(): - ConversionTest().UInt16Field = "spam" + with pytest.raises(TypeError): + ConversionTest().Int16Field = "spam" - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ConversionTest().Int16Field = None - def test(): - ConversionTest().UInt16Field = None + with pytest.raises(OverflowError): + ConversionTest().Int16Field = 32768 - self.assertRaises(TypeError, test) + with pytest.raises(OverflowError): + ConversionTest().Int16Field = -32769 - def test(): - ConversionTest().UInt16Field = 65536 + with pytest.raises(OverflowError): + _ = System.Int16(32768) - self.assertRaises(OverflowError, test) + with pytest.raises(OverflowError): + _ = System.Int16(-32769) - def test(): - ConversionTest().UInt16Field = -1 - self.assertRaises(OverflowError, test) +def test_int32_conversion(): + """Test int32 conversion.""" + assert System.Int32.MaxValue == 2147483647 + assert System.Int32.MinValue == -2147483648 - def test(): - value = System.UInt16(65536) + ob = ConversionTest() + assert ob.Int32Field == 0 - self.assertRaises(OverflowError, test) + ob.Int32Field = 2147483647 + assert ob.Int32Field == 2147483647 - def test(): - value = System.UInt16(-1) + ob.Int32Field = -2147483648 + assert ob.Int32Field == -2147483648 - self.assertRaises(OverflowError, test) + ob.Int32Field = System.Int32(2147483647) + assert ob.Int32Field == 2147483647 - def testUInt32Conversion(self): - """Test uint32 conversion.""" - self.assertTrue(System.UInt32.MaxValue == long(4294967295)) - self.assertTrue(System.UInt32.MinValue == 0) + ob.Int32Field = System.Int32(-2147483648) + assert ob.Int32Field == -2147483648 - object = ConversionTest() - self.assertTrue(object.UInt32Field == 0) + with pytest.raises(TypeError): + ConversionTest().Int32Field = "spam" - object.UInt32Field = long(4294967295) - self.assertTrue(object.UInt32Field == long(4294967295)) + with pytest.raises(TypeError): + ConversionTest().Int32Field = None - object.UInt32Field = -0 - self.assertTrue(object.UInt32Field == 0) + with pytest.raises(OverflowError): + ConversionTest().Int32Field = 2147483648 - object.UInt32Field = System.UInt32(long(4294967295)) - self.assertTrue(object.UInt32Field == long(4294967295)) + with pytest.raises(OverflowError): + ConversionTest().Int32Field = -2147483649 - object.UInt32Field = System.UInt32(0) - self.assertTrue(object.UInt32Field == 0) + with pytest.raises(OverflowError): + _ = System.Int32(2147483648) - def test(): - ConversionTest().UInt32Field = "spam" + with pytest.raises(OverflowError): + _ = System.Int32(-2147483649) - self.assertRaises(TypeError, test) - def test(): - ConversionTest().UInt32Field = None +def test_int64_conversion(): + """Test int64 conversion.""" + assert System.Int64.MaxValue == long(9223372036854775807) + assert System.Int64.MinValue == long(-9223372036854775808) - self.assertRaises(TypeError, test) + ob = ConversionTest() + assert ob.Int64Field == 0 - def test(): - ConversionTest().UInt32Field = long(4294967296) + ob.Int64Field = long(9223372036854775807) + assert ob.Int64Field == long(9223372036854775807) - self.assertRaises(OverflowError, test) + ob.Int64Field = long(-9223372036854775808) + assert ob.Int64Field == long(-9223372036854775808) - def test(): - ConversionTest().UInt32Field = -1 + ob.Int64Field = System.Int64(long(9223372036854775807)) + assert ob.Int64Field == long(9223372036854775807) - self.assertRaises(OverflowError, test) + ob.Int64Field = System.Int64(long(-9223372036854775808)) + assert ob.Int64Field == long(-9223372036854775808) - def test(): - value = System.UInt32(long(4294967296)) + with pytest.raises(TypeError): + ConversionTest().Int64Field = "spam" - self.assertRaises(OverflowError, test) + with pytest.raises(TypeError): + ConversionTest().Int64Field = None - def test(): - value = System.UInt32(-1) + with pytest.raises(OverflowError): + ConversionTest().Int64Field = long(9223372036854775808) - self.assertRaises(OverflowError, test) + with pytest.raises(OverflowError): + ConversionTest().Int64Field = long(-9223372036854775809) - def testUInt64Conversion(self): - """Test uint64 conversion.""" - self.assertTrue(System.UInt64.MaxValue == long(18446744073709551615)) - self.assertTrue(System.UInt64.MinValue == 0) + with pytest.raises(OverflowError): + _ = System.Int64(long(9223372036854775808)) - object = ConversionTest() - self.assertTrue(object.UInt64Field == 0) + with pytest.raises(OverflowError): + _ = System.Int64(long(-9223372036854775809)) - object.UInt64Field = long(18446744073709551615) - self.assertTrue(object.UInt64Field == long(18446744073709551615)) - object.UInt64Field = -0 - self.assertTrue(object.UInt64Field == 0) +def test_uint16_conversion(): + """Test uint16 conversion.""" + assert System.UInt16.MaxValue == 65535 + assert System.UInt16.MinValue == 0 - object.UInt64Field = System.UInt64(long(18446744073709551615)) - self.assertTrue(object.UInt64Field == long(18446744073709551615)) + ob = ConversionTest() + assert ob.UInt16Field == 0 - object.UInt64Field = System.UInt64(0) - self.assertTrue(object.UInt64Field == 0) + ob.UInt16Field = 65535 + assert ob.UInt16Field == 65535 - def test(): - ConversionTest().UInt64Field = "spam" + ob.UInt16Field = -0 + assert ob.UInt16Field == 0 - self.assertRaises(TypeError, test) + ob.UInt16Field = System.UInt16(65535) + assert ob.UInt16Field == 65535 - def test(): - ConversionTest().UInt64Field = None + ob.UInt16Field = System.UInt16(0) + assert ob.UInt16Field == 0 - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ConversionTest().UInt16Field = "spam" - def test(): - ConversionTest().UInt64Field = long(18446744073709551616) + with pytest.raises(TypeError): + ConversionTest().UInt16Field = None - self.assertRaises(OverflowError, test) + with pytest.raises(OverflowError): + ConversionTest().UInt16Field = 65536 - def test(): - ConversionTest().UInt64Field = -1 + with pytest.raises(OverflowError): + ConversionTest().UInt16Field = -1 - self.assertRaises(OverflowError, test) + with pytest.raises(OverflowError): + _ = System.UInt16(65536) - def test(): - value = System.UInt64(long(18446744073709551616)) + with pytest.raises(OverflowError): + _ = System.UInt16(-1) - self.assertRaises(OverflowError, test) - def test(): - value = System.UInt64(-1) +def test_uint32_conversion(): + """Test uint32 conversion.""" + assert System.UInt32.MaxValue == long(4294967295) + assert System.UInt32.MinValue == 0 - self.assertRaises(OverflowError, test) + ob = ConversionTest() + assert ob.UInt32Field == 0 - def testSingleConversion(self): - """Test single conversion.""" - self.assertTrue(System.Single.MaxValue == 3.402823e38) - self.assertTrue(System.Single.MinValue == -3.402823e38) + ob.UInt32Field = long(4294967295) + assert ob.UInt32Field == long(4294967295) - object = ConversionTest() - self.assertTrue(object.SingleField == 0.0) + ob.UInt32Field = -0 + assert ob.UInt32Field == 0 - object.SingleField = 3.402823e38 - self.assertTrue(object.SingleField == 3.402823e38) + ob.UInt32Field = System.UInt32(long(4294967295)) + assert ob.UInt32Field == long(4294967295) - object.SingleField = -3.402823e38 - self.assertTrue(object.SingleField == -3.402823e38) + ob.UInt32Field = System.UInt32(0) + assert ob.UInt32Field == 0 - object.SingleField = System.Single(3.402823e38) - self.assertTrue(object.SingleField == 3.402823e38) + with pytest.raises(TypeError): + ConversionTest().UInt32Field = "spam" - object.SingleField = System.Single(-3.402823e38) - self.assertTrue(object.SingleField == -3.402823e38) + with pytest.raises(TypeError): + ConversionTest().UInt32Field = None - def test(): - ConversionTest().SingleField = "spam" + with pytest.raises(OverflowError): + ConversionTest().UInt32Field = long(4294967296) - self.assertRaises(TypeError, test) + with pytest.raises(OverflowError): + ConversionTest().UInt32Field = -1 - def test(): - ConversionTest().SingleField = None + with pytest.raises(OverflowError): + _ = System.UInt32(long(4294967296)) - self.assertRaises(TypeError, test) + with pytest.raises(OverflowError): + _ = System.UInt32(-1) - def test(): - ConversionTest().SingleField = 3.402824e38 - self.assertRaises(OverflowError, test) +def test_uint64_conversion(): + """Test uint64 conversion.""" + assert System.UInt64.MaxValue == long(18446744073709551615) + assert System.UInt64.MinValue == 0 - def test(): - ConversionTest().SingleField = -3.402824e38 + ob = ConversionTest() + assert ob.UInt64Field == 0 - self.assertRaises(OverflowError, test) + ob.UInt64Field = long(18446744073709551615) + assert ob.UInt64Field == long(18446744073709551615) - def test(): - value = System.Single(3.402824e38) + ob.UInt64Field = -0 + assert ob.UInt64Field == 0 - self.assertRaises(OverflowError, test) + ob.UInt64Field = System.UInt64(long(18446744073709551615)) + assert ob.UInt64Field == long(18446744073709551615) - def test(): - value = System.Single(-3.402824e38) + ob.UInt64Field = System.UInt64(0) + assert ob.UInt64Field == 0 - self.assertRaises(OverflowError, test) + with pytest.raises(TypeError): + ConversionTest().UInt64Field = "spam" - def testDoubleConversion(self): - """Test double conversion.""" - self.assertTrue(System.Double.MaxValue == 1.7976931348623157e308) - self.assertTrue(System.Double.MinValue == -1.7976931348623157e308) + with pytest.raises(TypeError): + ConversionTest().UInt64Field = None - object = ConversionTest() - self.assertTrue(object.DoubleField == 0.0) + with pytest.raises(OverflowError): + ConversionTest().UInt64Field = long(18446744073709551616) - object.DoubleField = 1.7976931348623157e308 - self.assertTrue(object.DoubleField == 1.7976931348623157e308) + with pytest.raises(OverflowError): + ConversionTest().UInt64Field = -1 - object.DoubleField = -1.7976931348623157e308 - self.assertTrue(object.DoubleField == -1.7976931348623157e308) + with pytest.raises(OverflowError): + _ = System.UInt64(long(18446744073709551616)) - object.DoubleField = System.Double(1.7976931348623157e308) - self.assertTrue(object.DoubleField == 1.7976931348623157e308) + with pytest.raises(OverflowError): + _ = System.UInt64(-1) - object.DoubleField = System.Double(-1.7976931348623157e308) - self.assertTrue(object.DoubleField == -1.7976931348623157e308) - def test(): - ConversionTest().DoubleField = "spam" +def test_single_conversion(): + """Test single conversion.""" + assert System.Single.MaxValue == 3.402823e38 + assert System.Single.MinValue == -3.402823e38 - self.assertRaises(TypeError, test) + ob = ConversionTest() + assert ob.SingleField == 0.0 - def test(): - ConversionTest().DoubleField = None + ob.SingleField = 3.402823e38 + assert ob.SingleField == 3.402823e38 - self.assertRaises(TypeError, test) + ob.SingleField = -3.402823e38 + assert ob.SingleField == -3.402823e38 - def test(): - ConversionTest().DoubleField = 1.7976931348623159e308 + ob.SingleField = System.Single(3.402823e38) + assert ob.SingleField == 3.402823e38 - self.assertRaises(OverflowError, test) + ob.SingleField = System.Single(-3.402823e38) + assert ob.SingleField == -3.402823e38 - def test(): - ConversionTest().DoubleField = -1.7976931348623159e308 + with pytest.raises(TypeError): + ConversionTest().SingleField = "spam" - self.assertRaises(OverflowError, test) + with pytest.raises(TypeError): + ConversionTest().SingleField = None - def test(): - value = System.Double(1.7976931348623159e308) + with pytest.raises(OverflowError): + ConversionTest().SingleField = 3.402824e38 - self.assertRaises(OverflowError, test) + with pytest.raises(OverflowError): + ConversionTest().SingleField = -3.402824e38 - def test(): - value = System.Double(-1.7976931348623159e308) + with pytest.raises(OverflowError): + _ = System.Single(3.402824e38) - self.assertRaises(OverflowError, test) + with pytest.raises(OverflowError): + _ = System.Single(-3.402824e38) - def testDecimalConversion(self): - """Test decimal conversion.""" - from System import Decimal - max_d = Decimal.Parse("79228162514264337593543950335") - min_d = Decimal.Parse("-79228162514264337593543950335") +def test_double_conversion(): + """Test double conversion.""" + assert System.Double.MaxValue == 1.7976931348623157e308 + assert System.Double.MinValue == -1.7976931348623157e308 - self.assertTrue(Decimal.ToInt64(Decimal(10)) == long(10)) + ob = ConversionTest() + assert ob.DoubleField == 0.0 - object = ConversionTest() - self.assertTrue(object.DecimalField == Decimal(0)) + ob.DoubleField = 1.7976931348623157e308 + assert ob.DoubleField == 1.7976931348623157e308 - object.DecimalField = Decimal(10) - self.assertTrue(object.DecimalField == Decimal(10)) + ob.DoubleField = -1.7976931348623157e308 + assert ob.DoubleField == -1.7976931348623157e308 - object.DecimalField = Decimal.One - self.assertTrue(object.DecimalField == Decimal.One) + ob.DoubleField = System.Double(1.7976931348623157e308) + assert ob.DoubleField == 1.7976931348623157e308 - object.DecimalField = Decimal.Zero - self.assertTrue(object.DecimalField == Decimal.Zero) + ob.DoubleField = System.Double(-1.7976931348623157e308) + assert ob.DoubleField == -1.7976931348623157e308 - object.DecimalField = max_d - self.assertTrue(object.DecimalField == max_d) + with pytest.raises(TypeError): + ConversionTest().DoubleField = "spam" - object.DecimalField = min_d - self.assertTrue(object.DecimalField == min_d) + with pytest.raises(TypeError): + ConversionTest().DoubleField = None - def test(): - ConversionTest().DecimalField = None - self.assertRaises(TypeError, test) - def test(): - ConversionTest().DecimalField = "spam" +def test_decimal_conversion(): + """Test decimal conversion.""" + from System import Decimal - self.assertRaises(TypeError, test) + max_d = Decimal.Parse("79228162514264337593543950335") + min_d = Decimal.Parse("-79228162514264337593543950335") - def test(): - ConversionTest().DecimalField = 1 + assert Decimal.ToInt64(Decimal(10)) == long(10) - self.assertRaises(TypeError, test) + ob = ConversionTest() + assert ob.DecimalField == Decimal(0) - def testStringConversion(self): - """Test string / unicode conversion.""" - object = ConversionTest() + ob.DecimalField = Decimal(10) + assert ob.DecimalField == Decimal(10) - self.assertTrue(object.StringField == "spam") - self.assertTrue(object.StringField == six.u("spam")) + ob.DecimalField = Decimal.One + assert ob.DecimalField == Decimal.One - object.StringField = "eggs" - self.assertTrue(object.StringField == "eggs") - self.assertTrue(object.StringField == six.u("eggs")) + ob.DecimalField = Decimal.Zero + assert ob.DecimalField == Decimal.Zero - object.StringField = six.u("spam") - self.assertTrue(object.StringField == "spam") - self.assertTrue(object.StringField == six.u("spam")) + ob.DecimalField = max_d + assert ob.DecimalField == max_d - object.StringField = six.u('\uffff\uffff') - self.assertTrue(object.StringField == six.u('\uffff\uffff')) + ob.DecimalField = min_d + assert ob.DecimalField == min_d - object.StringField = System.String("spam") - self.assertTrue(object.StringField == "spam") - self.assertTrue(object.StringField == six.u("spam")) + with pytest.raises(TypeError): + ConversionTest().DecimalField = None - object.StringField = System.String(six.u('\uffff\uffff')) - self.assertTrue(object.StringField == six.u('\uffff\uffff')) + with pytest.raises(TypeError): + ConversionTest().DecimalField = "spam" - object.StringField = None - self.assertTrue(object.StringField == None) + with pytest.raises(TypeError): + ConversionTest().DecimalField = 1 - def test(): - ConversionTest().StringField = 1 - self.assertRaises(TypeError, test) +def test_string_conversion(): + """Test string / unicode conversion.""" + ob = ConversionTest() - def testInterfaceConversion(self): - """Test interface conversion.""" - from Python.Test import Spam, ISpam + assert ob.StringField == "spam" + assert ob.StringField == u"spam" - object = ConversionTest() + ob.StringField = "eggs" + assert ob.StringField == "eggs" + assert ob.StringField == u"eggs" - self.assertTrue(ISpam(object.SpamField).GetValue() == "spam") - self.assertTrue(object.SpamField.GetValue() == "spam") + ob.StringField = u"spam" + assert ob.StringField == "spam" + assert ob.StringField == u"spam" - object.SpamField = Spam("eggs") - self.assertTrue(ISpam(object.SpamField).GetValue() == "eggs") - self.assertTrue(object.SpamField.GetValue() == "eggs") + ob.StringField = u'\uffff\uffff' + assert ob.StringField == u'\uffff\uffff' - # need to test spam subclass here. + ob.StringField = System.String("spam") + assert ob.StringField == "spam" + assert ob.StringField == u"spam" - object.SpamField = None - self.assertTrue(object.SpamField == None) + ob.StringField = System.String(u'\uffff\uffff') + assert ob.StringField == u'\uffff\uffff' - def test(): - object = ConversionTest() - object.SpamField = System.String("bad") + ob.StringField = None + assert ob.StringField is None - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ConversionTest().StringField = 1 - def test(): - object = ConversionTest() - object.SpamField = System.Int32(1) - self.assertRaises(TypeError, test) +def test_interface_conversion(): + """Test interface conversion.""" + from Python.Test import Spam, ISpam - def testObjectConversion(self): - """Test object conversion.""" - from Python.Test import Spam + ob = ConversionTest() - object = ConversionTest() - self.assertTrue(object.ObjectField == None) + assert ISpam(ob.SpamField).GetValue() == "spam" + assert ob.SpamField.GetValue() == "spam" - object.ObjectField = Spam("eggs") - self.assertTrue(object.ObjectField.__class__.__name__ == "Spam") - self.assertTrue(object.ObjectField.GetValue() == "eggs") + ob.SpamField = Spam("eggs") + assert ISpam(ob.SpamField).GetValue() == "eggs" + assert ob.SpamField.GetValue() == "eggs" - object.ObjectField = None - self.assertTrue(object.ObjectField == None) + # need to test spam subclass here. - object.ObjectField = System.String("spam") - self.assertTrue(object.ObjectField == "spam") + ob.SpamField = None + assert ob.SpamField is None - object.ObjectField = System.Int32(1) - self.assertTrue(object.ObjectField == 1) + with pytest.raises(TypeError): + ob = ConversionTest() + ob.SpamField = System.String("bad") - # need to test subclass here + with pytest.raises(TypeError): + ob = ConversionTest() + ob.SpamField = System.Int32(1) - def test(): - object = ConversionTest() - object.ObjectField = self - self.assertRaises(TypeError, test) +def test_object_conversion(): + """Test ob conversion.""" + from Python.Test import Spam - def testEnumConversion(self): - """Test enum conversion.""" - from Python.Test import ShortEnum + ob = ConversionTest() + assert ob.ObjectField is None - object = ConversionTest() - self.assertTrue(object.EnumField == ShortEnum.Zero) + ob.ObjectField = Spam("eggs") + assert ob.ObjectField.__class__.__name__ == "Spam" + assert ob.ObjectField.GetValue() == "eggs" - object.EnumField = ShortEnum.One - self.assertTrue(object.EnumField == ShortEnum.One) + ob.ObjectField = None + assert ob.ObjectField is None - object.EnumField = 0 - self.assertTrue(object.EnumField == ShortEnum.Zero) - self.assertTrue(object.EnumField == 0) + ob.ObjectField = System.String("spam") + assert ob.ObjectField == "spam" - object.EnumField = 1 - self.assertTrue(object.EnumField == ShortEnum.One) - self.assertTrue(object.EnumField == 1) + ob.ObjectField = System.Int32(1) + assert ob.ObjectField == 1 - def test(): - object = ConversionTest() - object.EnumField = 10 + # need to test subclass here - self.assertRaises(ValueError, test) + with pytest.raises(TypeError): + class Foo(object): + pass + ob = ConversionTest() + ob.ObjectField = Foo - def test(): - object = ConversionTest() - object.EnumField = 255 - self.assertRaises(ValueError, test) +def test_enum_conversion(): + """Test enum conversion.""" + from Python.Test import ShortEnum - def test(): - object = ConversionTest() - object.EnumField = 1000000 + ob = ConversionTest() + assert ob.EnumField == ShortEnum.Zero - self.assertRaises(OverflowError, test) + ob.EnumField = ShortEnum.One + assert ob.EnumField == ShortEnum.One - def test(): - object = ConversionTest() - object.EnumField = "spam" + ob.EnumField = 0 + assert ob.EnumField == ShortEnum.Zero + assert ob.EnumField == 0 - self.assertRaises(TypeError, test) + ob.EnumField = 1 + assert ob.EnumField == ShortEnum.One + assert ob.EnumField == 1 - def testNullConversion(self): - """Test null conversion.""" - object = ConversionTest() + with pytest.raises(ValueError): + ob = ConversionTest() + ob.EnumField = 10 - object.StringField = None - self.assertTrue(object.StringField == None) + with pytest.raises(ValueError): + ob = ConversionTest() + ob.EnumField = 255 - object.ObjectField = None - self.assertTrue(object.ObjectField == None) + with pytest.raises(OverflowError): + ob = ConversionTest() + ob.EnumField = 1000000 - object.SpamField = None - self.assertTrue(object.SpamField == None) + with pytest.raises(TypeError): + ob = ConversionTest() + ob.EnumField = "spam" - # Primitive types and enums should not be set to null. - def test(): - ConversionTest().Int32Field = None +def test_null_conversion(): + """Test null conversion.""" + import System + + ob = ConversionTest() - self.assertRaises(TypeError, test) + ob.StringField = None + assert ob.StringField is None - def test(): - ConversionTest().EnumField = None + ob.ObjectField = None + assert ob.ObjectField is None - self.assertRaises(TypeError, test) + ob.SpamField = None + assert ob.SpamField is None - def testByteArrayConversion(self): - """Test byte array conversion.""" - object = ConversionTest() + pi = 22/7 + assert ob.Echo[System.Double](pi) == pi + assert ob.Echo[System.DateTime](None) is None - self.assertTrue(object.ByteArrayField == None) + # Primitive types and enums should not be set to null. - object.ByteArrayField = [0, 1, 2, 3, 4] - array = object.ByteArrayField - self.assertTrue(len(array) == 5) - self.assertTrue(array[0] == 0) - self.assertTrue(array[4] == 4) + with pytest.raises(TypeError): + ConversionTest().Int32Field = None - value = six.b("testing") - object.ByteArrayField = value - array = object.ByteArrayField - for i in range(len(value)): - self.assertTrue(array[i] == six.indexbytes(value, i)) + with pytest.raises(TypeError): + ConversionTest().EnumField = None - def testSByteArrayConversion(self): - """Test sbyte array conversion.""" - object = ConversionTest() - self.assertTrue(object.SByteArrayField == None) +def test_byte_array_conversion(): + """Test byte array conversion.""" + ob = ConversionTest() - object.SByteArrayField = [0, 1, 2, 3, 4] - array = object.SByteArrayField - self.assertTrue(len(array) == 5) - self.assertTrue(array[0] == 0) - self.assertTrue(array[4] == 4) + assert ob.ByteArrayField is None - value = six.b("testing") - object.SByteArrayField = value - array = object.SByteArrayField - for i in range(len(value)): - self.assertTrue(array[i] == six.indexbytes(value, i)) + ob.ByteArrayField = [0, 1, 2, 3, 4] + array = ob.ByteArrayField + assert len(array) == 5 + assert array[0] == 0 + assert array[4] == 4 + value = b"testing" + ob.ByteArrayField = value + array = ob.ByteArrayField + for i, _ in enumerate(value): + assert array[i] == indexbytes(value, i) -def test_suite(): - return unittest.makeSuite(ConversionTests) +def test_sbyte_array_conversion(): + """Test sbyte array conversion.""" + ob = ConversionTest() -def main(): - unittest.TextTestRunner().run(test_suite()) + assert ob.SByteArrayField is None + ob.SByteArrayField = [0, 1, 2, 3, 4] + array = ob.SByteArrayField + assert len(array) == 5 + assert array[0] == 0 + assert array[4] == 4 -if __name__ == '__main__': - main() + value = b"testing" + ob.SByteArrayField = value + array = ob.SByteArrayField + for i, _ in enumerate(value): + assert array[i] == indexbytes(value, i) diff --git a/src/tests/test_delegate.py b/src/tests/test_delegate.py index 26b85ec5e..33aca43b3 100644 --- a/src/tests/test_delegate.py +++ b/src/tests/test_delegate.py @@ -1,326 +1,269 @@ -import clr +# -*- coding: utf-8 -*- +# TODO: Add test for ObjectDelegate -clr.AddReference('Python.Test') +"""Test CLR delegate support.""" -from Python.Test import DelegateTest, PublicDelegate -from Python.Test import StringDelegate, ObjectDelegate -from Python.Test import BoolDelegate -import sys, os, string, unittest, types import Python.Test as Test import System -import six +import pytest +from Python.Test import DelegateTest, StringDelegate -if six.PY3: - DictProxyType = type(object.__dict__) -else: - DictProxyType = types.DictProxyType +from ._compat import DictProxyType +from .utils import HelloClass, hello_func, MultipleHandler -class DelegateTests(unittest.TestCase): - """Test CLR delegate support.""" +def test_delegate_standard_attrs(): + """Test standard delegate attributes.""" + from Python.Test import PublicDelegate - def testDelegateStandardAttrs(self): - """Test standard delegate attributes.""" - self.assertTrue(PublicDelegate.__name__ == 'PublicDelegate') - self.assertTrue(PublicDelegate.__module__ == 'Python.Test') - self.assertTrue(type(PublicDelegate.__dict__) == DictProxyType) - self.assertTrue(PublicDelegate.__doc__ == None) + assert PublicDelegate.__name__ == 'PublicDelegate' + assert PublicDelegate.__module__ == 'Python.Test' + assert isinstance(PublicDelegate.__dict__, DictProxyType) + assert PublicDelegate.__doc__ is None - def testGlobalDelegateVisibility(self): - """Test visibility of module-level delegates.""" - from Python.Test import PublicDelegate - self.assertTrue(PublicDelegate.__name__ == 'PublicDelegate') - self.assertTrue(Test.PublicDelegate.__name__ == 'PublicDelegate') +def test_global_delegate_visibility(): + """Test visibility of module-level delegates.""" + from Python.Test import PublicDelegate - def test(): - from Python.Test import InternalDelegate + assert PublicDelegate.__name__ == 'PublicDelegate' + assert Test.PublicDelegate.__name__ == 'PublicDelegate' - self.assertRaises(ImportError, test) + with pytest.raises(ImportError): + from Python.Test import InternalDelegate + _ = InternalDelegate - def test(): - i = Test.InternalDelegate + with pytest.raises(AttributeError): + _ = Test.InternalDelegate - self.assertRaises(AttributeError, test) - def testNestedDelegateVisibility(self): - """Test visibility of nested delegates.""" - ob = DelegateTest.PublicDelegate - self.assertTrue(ob.__name__ == 'PublicDelegate') +def test_nested_delegate_visibility(): + """Test visibility of nested delegates.""" + ob = DelegateTest.PublicDelegate + assert ob.__name__ == 'PublicDelegate' - ob = DelegateTest.ProtectedDelegate - self.assertTrue(ob.__name__ == 'ProtectedDelegate') + ob = DelegateTest.ProtectedDelegate + assert ob.__name__ == 'ProtectedDelegate' - def test(): - ob = DelegateTest.InternalDelegate + with pytest.raises(AttributeError): + _ = DelegateTest.InternalDelegate - self.assertRaises(AttributeError, test) + with pytest.raises(AttributeError): + _ = DelegateTest.PrivateDelegate - def test(): - ob = DelegateTest.PrivateDelegate - self.assertRaises(AttributeError, test) +def test_delegate_from_function(): + """Test delegate implemented with a Python function.""" - def testDelegateFromFunction(self): - """Test delegate implemented with a Python function.""" + d = StringDelegate(hello_func) + ob = DelegateTest() - def sayhello(): - return "hello" + assert ob.CallStringDelegate(d) == "hello" + assert d() == "hello" - d = StringDelegate(sayhello) - ob = DelegateTest() + ob.stringDelegate = d + assert ob.CallStringDelegate(ob.stringDelegate) == "hello" + assert ob.stringDelegate() == "hello" - self.assertTrue(ob.CallStringDelegate(d) == "hello") - self.assertTrue(d() == "hello") - ob.stringDelegate = d - self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.assertTrue(ob.stringDelegate() == "hello") +def test_delegate_from_method(): + """Test delegate implemented with a Python instance method.""" - def testDelegateFromMethod(self): - """Test delegate implemented with a Python instance method.""" + inst = HelloClass() + d = StringDelegate(inst.hello) + ob = DelegateTest() - class Hello: - def sayhello(self): - return "hello" + assert ob.CallStringDelegate(d) == "hello" + assert d() == "hello" - inst = Hello() - d = StringDelegate(inst.sayhello) - ob = DelegateTest() + ob.stringDelegate = d + assert ob.CallStringDelegate(ob.stringDelegate) == "hello" + assert ob.stringDelegate() == "hello" - self.assertTrue(ob.CallStringDelegate(d) == "hello") - self.assertTrue(d() == "hello") - ob.stringDelegate = d - self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.assertTrue(ob.stringDelegate() == "hello") +def test_delegate_from_unbound_method(): + """Test failure mode for unbound methods.""" - def testDelegateFromUnboundMethod(self): - """Test failure mode for unbound methods.""" + with pytest.raises(TypeError): + d = StringDelegate(HelloClass.hello) + d() - class Hello: - def sayhello(self): - return "hello" - def test(): - d = StringDelegate(Hello.sayhello) - d() +def test_delegate_from_static_method(): + """Test delegate implemented with a Python static method.""" - self.assertRaises(TypeError, test) + d = StringDelegate(HelloClass.s_hello) + ob = DelegateTest() - def testDelegateFromStaticMethod(self): - """Test delegate implemented with a Python static method.""" + assert ob.CallStringDelegate(d) == "hello" + assert d() == "hello" - class Hello: - def sayhello(): - return "hello" + ob.stringDelegate = d + assert ob.CallStringDelegate(ob.stringDelegate) == "hello" + assert ob.stringDelegate() == "hello" - sayhello = staticmethod(sayhello) + inst = HelloClass() + d = StringDelegate(inst.s_hello) + ob = DelegateTest() - d = StringDelegate(Hello.sayhello) - ob = DelegateTest() + assert ob.CallStringDelegate(d) == "hello" + assert d() == "hello" - self.assertTrue(ob.CallStringDelegate(d) == "hello") - self.assertTrue(d() == "hello") + ob.stringDelegate = d + assert ob.CallStringDelegate(ob.stringDelegate) == "hello" + assert ob.stringDelegate() == "hello" - ob.stringDelegate = d - self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.assertTrue(ob.stringDelegate() == "hello") - inst = Hello() - d = StringDelegate(inst.sayhello) - ob = DelegateTest() +def test_delegate_from_class_method(): + """Test delegate implemented with a Python class method.""" - self.assertTrue(ob.CallStringDelegate(d) == "hello") - self.assertTrue(d() == "hello") + d = StringDelegate(HelloClass.c_hello) + ob = DelegateTest() - ob.stringDelegate = d - self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.assertTrue(ob.stringDelegate() == "hello") + assert ob.CallStringDelegate(d) == "hello" + assert d() == "hello" - def testDelegateFromClassMethod(self): - """Test delegate implemented with a Python class method.""" + ob.stringDelegate = d + assert ob.CallStringDelegate(ob.stringDelegate) == "hello" + assert ob.stringDelegate() == "hello" - class Hello: - def sayhello(self): - return "hello" + inst = HelloClass() + d = StringDelegate(inst.c_hello) + ob = DelegateTest() - sayhello = classmethod(sayhello) + assert ob.CallStringDelegate(d) == "hello" + assert d() == "hello" - d = StringDelegate(Hello.sayhello) - ob = DelegateTest() + ob.stringDelegate = d + assert ob.CallStringDelegate(ob.stringDelegate) == "hello" + assert ob.stringDelegate() == "hello" - self.assertTrue(ob.CallStringDelegate(d) == "hello") - self.assertTrue(d() == "hello") - ob.stringDelegate = d - self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.assertTrue(ob.stringDelegate() == "hello") +def test_delegate_from_callable(): + """Test delegate implemented with a Python callable object.""" - inst = Hello() - d = StringDelegate(inst.sayhello) - ob = DelegateTest() + inst = HelloClass() + d = StringDelegate(inst) + ob = DelegateTest() - self.assertTrue(ob.CallStringDelegate(d) == "hello") - self.assertTrue(d() == "hello") + assert ob.CallStringDelegate(d) == "hello" + assert d() == "hello" - ob.stringDelegate = d - self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.assertTrue(ob.stringDelegate() == "hello") + ob.stringDelegate = d + assert ob.CallStringDelegate(ob.stringDelegate) == "hello" + assert ob.stringDelegate() == "hello" - def testDelegateFromCallable(self): - """Test delegate implemented with a Python callable object.""" - class Hello: - def __call__(self): - return "hello" +def test_delegate_from_managed_instance_method(): + """Test delegate implemented with a managed instance method.""" + ob = DelegateTest() + d = StringDelegate(ob.SayHello) - inst = Hello() - d = StringDelegate(inst) - ob = DelegateTest() + assert ob.CallStringDelegate(d) == "hello" + assert d() == "hello" - self.assertTrue(ob.CallStringDelegate(d) == "hello") - self.assertTrue(d() == "hello") + ob.stringDelegate = d + assert ob.CallStringDelegate(ob.stringDelegate) == "hello" + assert ob.stringDelegate() == "hello" - ob.stringDelegate = d - self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.assertTrue(ob.stringDelegate() == "hello") - def testDelegateFromManagedInstanceMethod(self): - """Test delegate implemented with a managed instance method.""" - ob = DelegateTest() - d = StringDelegate(ob.SayHello) +def test_delegate_from_managed_static_method(): + """Test delegate implemented with a managed static method.""" + d = StringDelegate(DelegateTest.StaticSayHello) + ob = DelegateTest() - self.assertTrue(ob.CallStringDelegate(d) == "hello") - self.assertTrue(d() == "hello") + assert ob.CallStringDelegate(d) == "hello" + assert d() == "hello" - ob.stringDelegate = d - self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.assertTrue(ob.stringDelegate() == "hello") + ob.stringDelegate = d + assert ob.CallStringDelegate(ob.stringDelegate) == "hello" + assert ob.stringDelegate() == "hello" - def testDelegateFromManagedStaticMethod(self): - """Test delegate implemented with a managed static method.""" - d = StringDelegate(DelegateTest.StaticSayHello) - ob = DelegateTest() - self.assertTrue(ob.CallStringDelegate(d) == "hello") - self.assertTrue(d() == "hello") +def test_delegate_from_delegate(): + """Test delegate implemented with another delegate.""" + d1 = StringDelegate(hello_func) + d2 = StringDelegate(d1) + ob = DelegateTest() - ob.stringDelegate = d - self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.assertTrue(ob.stringDelegate() == "hello") + assert ob.CallStringDelegate(d2) == "hello" + assert d2() == "hello" - def testDelegateFromDelegate(self): - """Test delegate implemented with another delegate.""" + ob.stringDelegate = d2 + assert ob.CallStringDelegate(ob.stringDelegate) == "hello" + assert ob.stringDelegate() == "hello" - def sayhello(): - return "hello" - d1 = StringDelegate(sayhello) - d2 = StringDelegate(d1) - ob = DelegateTest() +def test_delegate_with_invalid_args(): + """Test delegate instantiation with invalid (non-callable) args.""" - self.assertTrue(ob.CallStringDelegate(d2) == "hello") - self.assertTrue(d2() == "hello") + with pytest.raises(TypeError): + _ = StringDelegate(None) - ob.stringDelegate = d2 - self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.assertTrue(ob.stringDelegate() == "hello") + with pytest.raises(TypeError): + _ = StringDelegate("spam") - def testDelegateWithInvalidArgs(self): - """Test delegate instantiation with invalid (non-callable) args.""" + with pytest.raises(TypeError): + _ = StringDelegate(1) - def test(): - d = StringDelegate(None) - self.assertRaises(TypeError, test) +def test_multicast_delegate(): + """Test multicast delegates.""" - def test(): - d = StringDelegate("spam") + inst = MultipleHandler() + d1 = StringDelegate(inst.count) + d2 = StringDelegate(inst.count) - self.assertRaises(TypeError, test) + md = System.Delegate.Combine(d1, d2) + ob = DelegateTest() - def test(): - d = StringDelegate(1) + assert ob.CallStringDelegate(md) == "ok" + assert inst.value == 2 - self.assertRaises(TypeError, test) + assert md() == "ok" + assert inst.value == 4 - def testMulticastDelegate(self): - """Test multicast delegates.""" - class Multi: - def __init__(self): - self.value = 0 +def test_subclass_delegate_fails(): + """Test that subclassing of a delegate type fails.""" + from Python.Test import PublicDelegate - def count(self): - self.value += 1 - return 'ok' + with pytest.raises(TypeError): + class Boom(PublicDelegate): + pass - inst = Multi() - d1 = StringDelegate(inst.count) - d2 = StringDelegate(inst.count) + _ = Boom - md = System.Delegate.Combine(d1, d2) - ob = DelegateTest() - self.assertTrue(ob.CallStringDelegate(md) == "ok") - self.assertTrue(inst.value == 2) +def test_delegate_equality(): + """Test delegate equality.""" - self.assertTrue(md() == "ok") - self.assertTrue(inst.value == 4) + d = StringDelegate(hello_func) + ob = DelegateTest() + ob.stringDelegate = d + assert ob.stringDelegate == d - def testSubclassDelegateFails(self): - """Test that subclassing of a delegate type fails.""" - def test(): - class Boom(PublicDelegate): - pass +def test_bool_delegate(): + """Test boolean delegate.""" + from Python.Test import BoolDelegate - self.assertRaises(TypeError, test) + def always_so_negative(): + return 0 - def testDelegateEquality(self): - """Test delegate equality.""" + d = BoolDelegate(always_so_negative) + ob = DelegateTest() + ob.CallBoolDelegate(d) - def sayhello(): - return "hello" + assert not d() + assert not ob.CallBoolDelegate(d) - d = StringDelegate(sayhello) - ob = DelegateTest() - ob.stringDelegate = d - self.assertTrue(ob.stringDelegate == d) + # test async delegates - def testBoolDelegate(self): - """Test boolean delegate.""" + # test multicast delegates - def always_so_negative(): - return 0 + # test explicit op_ - d = BoolDelegate(always_so_negative) - ob = DelegateTest() - ob.CallBoolDelegate(d) + # test sig mismatch, both on managed and Python side - self.assertTrue(not d()) - - self.assertTrue(not ob.CallBoolDelegate(d)) - - # test async delegates - - # test multicast delegates - - # test explicit op_ - - # test sig mismatch, both on managed and Python side - - # test return wrong type - - -def test_suite(): - return unittest.makeSuite(DelegateTests) - - -def main(): - unittest.TextTestRunner().run(test_suite()) - - -if __name__ == '__main__': - main() + # test return wrong type diff --git a/src/tests/test_docstring.py b/src/tests/test_docstring.py index 9eaea09bb..640a61915 100644 --- a/src/tests/test_docstring.py +++ b/src/tests/test_docstring.py @@ -1,37 +1,27 @@ -import unittest -import clr +# -*- coding: utf-8 -*- -clr.AddReference('Python.Test') +"""Test doc strings support.""" -from Python.Test import DocWithCtorTest, DocWithoutCtorTest, DocWithCtorNoDocTest +def test_doc_with_ctor(): + from Python.Test import DocWithCtorTest -class DocStringTests(unittest.TestCase): - """Test doc strings support.""" + assert DocWithCtorTest.__doc__ == 'DocWithCtorTest Class' + assert DocWithCtorTest.TestMethod.__doc__ == 'DocWithCtorTest TestMethod' + assert DocWithCtorTest.StaticTestMethod.__doc__ == 'DocWithCtorTest StaticTestMethod' - def testDocWithCtor(self): - self.assertEqual(DocWithCtorTest.__doc__, 'DocWithCtorTest Class') - self.assertEqual(DocWithCtorTest.TestMethod.__doc__, 'DocWithCtorTest TestMethod') - self.assertEqual(DocWithCtorTest.StaticTestMethod.__doc__, 'DocWithCtorTest StaticTestMethod') - def testDocWithCtorNoDoc(self): - self.assertEqual(DocWithCtorNoDocTest.__doc__, 'Void .ctor(Boolean)') - self.assertEqual(DocWithCtorNoDocTest.TestMethod.__doc__, 'Void TestMethod(Double, Int32)') - self.assertEqual(DocWithCtorNoDocTest.StaticTestMethod.__doc__, 'Void StaticTestMethod(Double, Int32)') +def test_doc_with_ctor_no_doc(): + from Python.Test import DocWithCtorNoDocTest - def testDocWithoutCtor(self): - self.assertEqual(DocWithoutCtorTest.__doc__, 'DocWithoutCtorTest Class') - self.assertEqual(DocWithoutCtorTest.TestMethod.__doc__, 'DocWithoutCtorTest TestMethod') - self.assertEqual(DocWithoutCtorTest.StaticTestMethod.__doc__, 'DocWithoutCtorTest StaticTestMethod') + assert DocWithCtorNoDocTest.__doc__ == 'Void .ctor(Boolean)' + assert DocWithCtorNoDocTest.TestMethod.__doc__ == 'Void TestMethod(Double, Int32)' + assert DocWithCtorNoDocTest.StaticTestMethod.__doc__ == 'Void StaticTestMethod(Double, Int32)' -def test_suite(): - return unittest.makeSuite(DocStringTests) +def test_doc_without_ctor(): + from Python.Test import DocWithoutCtorTest - -def main(): - unittest.TextTestRunner().run(test_suite()) - - -if __name__ == '__main__': - main() + assert DocWithoutCtorTest.__doc__ == 'DocWithoutCtorTest Class' + assert DocWithoutCtorTest.TestMethod.__doc__ == 'DocWithoutCtorTest TestMethod' + assert DocWithoutCtorTest.StaticTestMethod.__doc__ == 'DocWithoutCtorTest StaticTestMethod' diff --git a/src/tests/test_engine.py b/src/tests/test_engine.py index 43437c779..60fdbf45d 100644 --- a/src/tests/test_engine.py +++ b/src/tests/test_engine.py @@ -1,46 +1,43 @@ -import sys, os, string, unittest, types -from Python.Runtime import PythonEngine - - -# XXX This test module isn't used! +# -*- coding: utf-8 -*- -class EngineTests(unittest.TestCase): - """Test PythonEngine embedding APIs.""" +"""Test PythonEngine embedding APIs.""" - def testMultipleCallsToInitialize(self): - """Test that multiple initialize calls are harmless.""" - PythonEngine.Initialize(); - PythonEngine.Initialize(); - PythonEngine.Initialize(); +import sys - def testImportModule(self): - """Test module import.""" - m = PythonEngine.ImportModule("sys") - n = m.GetAttr("__name__") - self.assertTrue(n.AsManagedObject(System.String) == "sys") - - def testRunString(self): - """Test the RunString method.""" - PythonEngine.AcquireLock() +import System +import pytest +from Python.Runtime import PythonEngine - code = "import sys; sys.singleline_worked = 1" - PythonEngine.RunString(code) - self.assertTrue(sys.singleline_worked == 1) - code = "import sys\nsys.multiline_worked = 1" - PythonEngine.RunString(code) - self.assertTrue(sys.multiline_worked == 1) +def test_multiple_calls_to_initialize(): + """Test that multiple initialize calls are harmless.""" + try: + PythonEngine.Initialize() + PythonEngine.Initialize() + PythonEngine.Initialize() + except Exception: + assert False # Initialize() raise an exception. - PythonEngine.ReleaseLock() +@pytest.mark.skip(reason="FIXME: test crashes") +def test_import_module(): + """Test module import.""" + m = PythonEngine.ImportModule("sys") + n = m.GetAttr("__name__") + assert n.AsManagedObject(System.String) == "sys" -def test_suite(): - return unittest.makeSuite(EngineTests) +@pytest.mark.skip(reason="FIXME: test freezes") +def test_run_string(): + """Test the RunString method.""" + PythonEngine.AcquireLock() -def main(): - unittest.TextTestRunner().run(test_suite()) + code = "import sys; sys.singleline_worked = 1" + PythonEngine.RunString(code) + assert sys.singleline_worked == 1 + code = "import sys\nsys.multiline_worked = 1" + PythonEngine.RunString(code) + assert sys.multiline_worked == 1 -if __name__ == '__main__': - main() + PythonEngine.ReleaseLock() diff --git a/src/tests/test_enum.py b/src/tests/test_enum.py index fae32bbe6..b31ce4ec5 100644 --- a/src/tests/test_enum.py +++ b/src/tests/test_enum.py @@ -1,155 +1,145 @@ -import sys, os, string, unittest, types -from System import DayOfWeek -from Python import Test -import six - -if six.PY3: - DictProxyType = type(object.__dict__) - long = int -else: - DictProxyType = types.DictProxyType - - -class EnumTests(unittest.TestCase): - """Test CLR enum support.""" - - def testEnumStandardAttrs(self): - """Test standard enum attributes.""" - self.assertTrue(DayOfWeek.__name__ == 'DayOfWeek') - self.assertTrue(DayOfWeek.__module__ == 'System') - self.assertTrue(type(DayOfWeek.__dict__) == DictProxyType) - self.assertTrue(DayOfWeek.__doc__ == None) - - def testEnumGetMember(self): - """Test access to enum members.""" - self.assertTrue(DayOfWeek.Sunday == 0) - self.assertTrue(DayOfWeek.Monday == 1) - self.assertTrue(DayOfWeek.Tuesday == 2) - self.assertTrue(DayOfWeek.Wednesday == 3) - self.assertTrue(DayOfWeek.Thursday == 4) - self.assertTrue(DayOfWeek.Friday == 5) - self.assertTrue(DayOfWeek.Saturday == 6) - - def testByteEnum(self): - """Test byte enum.""" - self.assertTrue(Test.ByteEnum.Zero == 0) - self.assertTrue(Test.ByteEnum.One == 1) - self.assertTrue(Test.ByteEnum.Two == 2) - - def testSByteEnum(self): - """Test sbyte enum.""" - self.assertTrue(Test.SByteEnum.Zero == 0) - self.assertTrue(Test.SByteEnum.One == 1) - self.assertTrue(Test.SByteEnum.Two == 2) +# -*- coding: utf-8 -*- - def testShortEnum(self): - """Test short enum.""" - self.assertTrue(Test.ShortEnum.Zero == 0) - self.assertTrue(Test.ShortEnum.One == 1) - self.assertTrue(Test.ShortEnum.Two == 2) +"""Test clr enum support.""" - def testUShortEnum(self): - """Test ushort enum.""" - self.assertTrue(Test.UShortEnum.Zero == 0) - self.assertTrue(Test.UShortEnum.One == 1) - self.assertTrue(Test.UShortEnum.Two == 2) +import pytest +import Python.Test as Test - def testIntEnum(self): - """Test int enum.""" - self.assertTrue(Test.IntEnum.Zero == 0) - self.assertTrue(Test.IntEnum.One == 1) - self.assertTrue(Test.IntEnum.Two == 2) +from ._compat import DictProxyType, long - def testUIntEnum(self): - """Test uint enum.""" - self.assertTrue(Test.UIntEnum.Zero == long(0)) - self.assertTrue(Test.UIntEnum.One == long(1)) - self.assertTrue(Test.UIntEnum.Two == long(2)) - def testLongEnum(self): - """Test long enum.""" - self.assertTrue(Test.LongEnum.Zero == long(0)) - self.assertTrue(Test.LongEnum.One == long(1)) - self.assertTrue(Test.LongEnum.Two == long(2)) +def test_enum_standard_attrs(): + """Test standard enum attributes.""" + from System import DayOfWeek - def testULongEnum(self): - """Test ulong enum.""" - self.assertTrue(Test.ULongEnum.Zero == long(0)) - self.assertTrue(Test.ULongEnum.One == long(1)) - self.assertTrue(Test.ULongEnum.Two == long(2)) + assert DayOfWeek.__name__ == 'DayOfWeek' + assert DayOfWeek.__module__ == 'System' + assert isinstance(DayOfWeek.__dict__, DictProxyType) + assert DayOfWeek.__doc__ is None - def testInstantiateEnumFails(self): - """Test that instantiation of an enum class fails.""" - def test(): - ob = DayOfWeek() +def test_enum_get_member(): + """Test access to enum members.""" + from System import DayOfWeek - self.assertRaises(TypeError, test) + assert DayOfWeek.Sunday == 0 + assert DayOfWeek.Monday == 1 + assert DayOfWeek.Tuesday == 2 + assert DayOfWeek.Wednesday == 3 + assert DayOfWeek.Thursday == 4 + assert DayOfWeek.Friday == 5 + assert DayOfWeek.Saturday == 6 - def testSubclassEnumFails(self): - """Test that subclassing of an enumeration fails.""" - def test(): - class Boom(DayOfWeek): - pass +def test_byte_enum(): + """Test byte enum.""" + assert Test.ByteEnum.Zero == 0 + assert Test.ByteEnum.One == 1 + assert Test.ByteEnum.Two == 2 - self.assertRaises(TypeError, test) - def testEnumSetMemberFails(self): - """Test that setattr operations on enumerations fail.""" +def test_sbyte_enum(): + """Test sbyte enum.""" + assert Test.SByteEnum.Zero == 0 + assert Test.SByteEnum.One == 1 + assert Test.SByteEnum.Two == 2 - def test(): - DayOfWeek.Sunday = 13 - self.assertRaises(TypeError, test) +def test_short_enum(): + """Test short enum.""" + assert Test.ShortEnum.Zero == 0 + assert Test.ShortEnum.One == 1 + assert Test.ShortEnum.Two == 2 - def test(): - del DayOfWeek.Sunday - self.assertRaises(TypeError, test) +def test_ushort_enum(): + """Test ushort enum.""" + assert Test.UShortEnum.Zero == 0 + assert Test.UShortEnum.One == 1 + assert Test.UShortEnum.Two == 2 - def testEnumWithFlagsAttrConversion(self): - """Test enumeration conversion with FlagsAttribute set.""" - # This works because the FlagsField enum has FlagsAttribute. - Test.FieldTest().FlagsField = 99 - # This should fail because our test enum doesn't have it. - def test(): - Test.FieldTest().EnumField = 99 +def test_int_enum(): + """Test int enum.""" + assert Test.IntEnum.Zero == 0 + assert Test.IntEnum.One == 1 + assert Test.IntEnum.Two == 2 - self.assertRaises(ValueError, test) - def testEnumConversion(self): - """Test enumeration conversion.""" - object = Test.FieldTest() - self.assertTrue(object.EnumField == 0) +def test_uint_enum(): + """Test uint enum.""" + assert Test.UIntEnum.Zero == long(0) + assert Test.UIntEnum.One == long(1) + assert Test.UIntEnum.Two == long(2) - object.EnumField = Test.ShortEnum.One - self.assertTrue(object.EnumField == 1) - def test(): - Test.FieldTest().EnumField = 20 +def test_long_enum(): + """Test long enum.""" + assert Test.LongEnum.Zero == long(0) + assert Test.LongEnum.One == long(1) + assert Test.LongEnum.Two == long(2) - self.assertRaises(ValueError, test) - def test(): - Test.FieldTest().EnumField = 100000 +def test_ulong_enum(): + """Test ulong enum.""" + assert Test.ULongEnum.Zero == long(0) + assert Test.ULongEnum.One == long(1) + assert Test.ULongEnum.Two == long(2) - self.assertRaises(OverflowError, test) - def test(): - Test.FieldTest().EnumField = "str" +def test_instantiate_enum_fails(): + """Test that instantiation of an enum class fails.""" + from System import DayOfWeek - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + _ = DayOfWeek() -def test_suite(): - return unittest.makeSuite(EnumTests) +def test_subclass_enum_fails(): + """Test that subclassing of an enumeration fails.""" + from System import DayOfWeek + with pytest.raises(TypeError): + class Boom(DayOfWeek): + pass -def main(): - unittest.TextTestRunner().run(test_suite()) + _ = Boom -if __name__ == '__main__': - main() +def test_enum_set_member_fails(): + """Test that setattr operations on enumerations fail.""" + from System import DayOfWeek + + with pytest.raises(TypeError): + DayOfWeek.Sunday = 13 + + with pytest.raises(TypeError): + del DayOfWeek.Sunday + + +def test_enum_with_flags_attr_conversion(): + """Test enumeration conversion with FlagsAttribute set.""" + # This works because the FlagsField enum has FlagsAttribute. + Test.FieldTest().FlagsField = 99 + + # This should fail because our test enum doesn't have it. + with pytest.raises(ValueError): + Test.FieldTest().EnumField = 99 + + +def test_enum_conversion(): + """Test enumeration conversion.""" + ob = Test.FieldTest() + assert ob.EnumField == 0 + + ob.EnumField = Test.ShortEnum.One + assert ob.EnumField == 1 + + with pytest.raises(ValueError): + Test.FieldTest().EnumField = 20 + + with pytest.raises(OverflowError): + Test.FieldTest().EnumField = 100000 + + with pytest.raises(TypeError): + Test.FieldTest().EnumField = "str" diff --git a/src/tests/test_event.py b/src/tests/test_event.py index c68f9629a..624b83d44 100644 --- a/src/tests/test_event.py +++ b/src/tests/test_event.py @@ -1,686 +1,584 @@ -import clr +# -*- coding: utf-8 -*- -clr.AddReference('Python.Test') +"""Test CLR event support.""" -import sys, os, string, unittest, types -from Python.Test import EventTest, TestEventHandler -from Python.Test import TestEventArgs +import pytest +from Python.Test import EventTest, EventArgsTest +from ._compat import range +from .utils import (CallableHandler, ClassMethodHandler, GenericHandler, + MultipleHandler, StaticMethodHandler, VarCallableHandler, + VariableArgsHandler) -class EventTests(unittest.TestCase): - """Test CLR event support.""" - def testPublicInstanceEvent(self): - """Test public instance events.""" - object = EventTest() +def test_public_instance_event(): + """Test public instance events.""" + ob = EventTest() - handler = GenericHandler() - self.assertTrue(handler.value == None) - - object.PublicEvent += handler.handler - - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 10) - - object.PublicEvent -= handler.handler - - def testPublicStaticEvent(self): - """Test public static events.""" - handler = GenericHandler() - self.assertTrue(handler.value == None) - - EventTest.PublicStaticEvent += handler.handler - - EventTest.OnPublicStaticEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 10) - - def testProtectedInstanceEvent(self): - """Test protected instance events.""" - object = EventTest() - - handler = GenericHandler() - self.assertTrue(handler.value == None) + handler = GenericHandler() + assert handler.value is None - object.ProtectedEvent += handler.handler + ob.PublicEvent += handler.handler - object.OnProtectedEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 10) + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 10 - object.ProtectedEvent -= handler.handler + ob.PublicEvent -= handler.handler - def testProtectedStaticEvent(self): - """Test protected static events.""" - object = EventTest - handler = GenericHandler() - self.assertTrue(handler.value == None) +def test_public_static_event(): + """Test public static events.""" + handler = GenericHandler() + assert handler.value is None - EventTest.ProtectedStaticEvent += handler.handler + EventTest.PublicStaticEvent += handler.handler - EventTest.OnProtectedStaticEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 10) + EventTest.OnPublicStaticEvent(EventArgsTest(10)) + assert handler.value == 10 - EventTest.ProtectedStaticEvent -= handler.handler - def testInternalEvents(self): - """Test internal events.""" +def test_protected_instance_event(): + """Test protected instance events.""" + ob = EventTest() - def test(): - f = EventTest().InternalEvent + handler = GenericHandler() + assert handler.value is None - self.assertRaises(AttributeError, test) + ob.ProtectedEvent += handler.handler - def test(): - f = EventTest().InternalStaticEvent + ob.OnProtectedEvent(EventArgsTest(10)) + assert handler.value == 10 - self.assertRaises(AttributeError, test) + ob.ProtectedEvent -= handler.handler - def test(): - f = EventTest.InternalStaticEvent - self.assertRaises(AttributeError, test) +def test_protected_static_event(): + """Test protected static events.""" + handler = GenericHandler() + assert handler.value is None - def testPrivateEvents(self): - """Test private events.""" + EventTest.ProtectedStaticEvent += handler.handler - def test(): - f = EventTest().PrivateEvent + EventTest.OnProtectedStaticEvent(EventArgsTest(10)) + assert handler.value == 10 - self.assertRaises(AttributeError, test) + EventTest.ProtectedStaticEvent -= handler.handler - def test(): - f = EventTest().PrivateStaticEvent - self.assertRaises(AttributeError, test) +def test_internal_events(): + """Test internal events.""" - def test(): - f = EventTest.PrivateStaticEvent + with pytest.raises(AttributeError): + _ = EventTest().InternalEvent - self.assertRaises(AttributeError, test) + with pytest.raises(AttributeError): + _ = EventTest().InternalStaticEvent - def testMulticastEvent(self): - """Test multicast events.""" - object = EventTest() + with pytest.raises(AttributeError): + _ = EventTest.InternalStaticEvent - handler1 = GenericHandler() - handler2 = GenericHandler() - handler3 = GenericHandler() - object.PublicEvent += handler1.handler - object.PublicEvent += handler2.handler - object.PublicEvent += handler3.handler +def test_private_events(): + """Test private events.""" - object.OnPublicEvent(TestEventArgs(10)) + with pytest.raises(AttributeError): + _ = EventTest().PrivateEvent - self.assertTrue(handler1.value == 10) - self.assertTrue(handler2.value == 10) - self.assertTrue(handler3.value == 10) + with pytest.raises(AttributeError): + _ = EventTest().PrivateStaticEvent - object.OnPublicEvent(TestEventArgs(20)) + with pytest.raises(AttributeError): + _ = EventTest.PrivateStaticEvent - self.assertTrue(handler1.value == 20) - self.assertTrue(handler2.value == 20) - self.assertTrue(handler3.value == 20) - object.PublicEvent -= handler1.handler - object.PublicEvent -= handler2.handler - object.PublicEvent -= handler3.handler +def test_multicast_event(): + """Test multicast events.""" + ob = EventTest() - def testInstanceMethodHandler(self): - """Test instance method handlers.""" - object = EventTest() - handler = GenericHandler() + handler1 = GenericHandler() + handler2 = GenericHandler() + handler3 = GenericHandler() - object.PublicEvent += handler.handler - self.assertTrue(handler.value == None) + ob.PublicEvent += handler1.handler + ob.PublicEvent += handler2.handler + ob.PublicEvent += handler3.handler - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 10) + ob.OnPublicEvent(EventArgsTest(10)) - object.PublicEvent -= handler.handler - self.assertTrue(handler.value == 10) + assert handler1.value == 10 + assert handler2.value == 10 + assert handler3.value == 10 - object.OnPublicEvent(TestEventArgs(20)) - self.assertTrue(handler.value == 10) + ob.OnPublicEvent(EventArgsTest(20)) - def testVarArgsInstanceMethodHandler(self): - """Test vararg instance method handlers.""" - object = EventTest() - handler = VariableArgsHandler() + assert handler1.value == 20 + assert handler2.value == 20 + assert handler3.value == 20 - object.PublicEvent += handler.handler - self.assertTrue(handler.value == None) + ob.PublicEvent -= handler1.handler + ob.PublicEvent -= handler2.handler + ob.PublicEvent -= handler3.handler - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 10) - object.PublicEvent -= handler.handler - self.assertTrue(handler.value == 10) +def test_instance_method_handler(): + """Test instance method handlers.""" + ob = EventTest() + handler = GenericHandler() - object.OnPublicEvent(TestEventArgs(20)) - self.assertTrue(handler.value == 10) + ob.PublicEvent += handler.handler + assert handler.value is None - def testCallableObjectHandler(self): - """Test callable object handlers.""" - object = EventTest() - handler = CallableHandler() + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 10 - object.PublicEvent += handler - self.assertTrue(handler.value == None) + ob.PublicEvent -= handler.handler + assert handler.value == 10 - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 10) + ob.OnPublicEvent(EventArgsTest(20)) + assert handler.value == 10 - object.PublicEvent -= handler - self.assertTrue(handler.value == 10) - object.OnPublicEvent(TestEventArgs(20)) - self.assertTrue(handler.value == 10) +def test_var_args_instance_method_handler(): + """Test vararg instance method handlers.""" + ob = EventTest() + handler = VariableArgsHandler() - def testVarArgsCallableHandler(self): - """Test varargs callable handlers.""" - object = EventTest() - handler = VarCallableHandler() + ob.PublicEvent += handler.handler + assert handler.value is None - object.PublicEvent += handler - self.assertTrue(handler.value == None) + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 10 - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 10) + ob.PublicEvent -= handler.handler + assert handler.value == 10 - object.PublicEvent -= handler - self.assertTrue(handler.value == 10) + ob.OnPublicEvent(EventArgsTest(20)) + assert handler.value == 10 - object.OnPublicEvent(TestEventArgs(20)) - self.assertTrue(handler.value == 10) - def testStaticMethodHandler(self): - """Test static method handlers.""" - object = EventTest() - handler = StaticMethodHandler() - StaticMethodHandler.value = None +def test_callableob_handler(): + """Test callable ob handlers.""" + ob = EventTest() + handler = CallableHandler() - object.PublicEvent += handler.handler - self.assertTrue(handler.value == None) + ob.PublicEvent += handler + assert handler.value is None - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 10) + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 10 - object.PublicEvent -= handler.handler - self.assertTrue(handler.value == 10) + ob.PublicEvent -= handler + assert handler.value == 10 - object.OnPublicEvent(TestEventArgs(20)) - self.assertTrue(handler.value == 10) + ob.OnPublicEvent(EventArgsTest(20)) + assert handler.value == 10 - def testClassMethodHandler(self): - """Test class method handlers.""" - object = EventTest() - handler = ClassMethodHandler() - ClassMethodHandler.value = None - object.PublicEvent += handler.handler - self.assertTrue(handler.value == None) +def test_var_args_callable_handler(): + """Test varargs callable handlers.""" + ob = EventTest() + handler = VarCallableHandler() - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 10) + ob.PublicEvent += handler + assert handler.value is None - object.PublicEvent -= handler.handler - self.assertTrue(handler.value == 10) + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 10 - object.OnPublicEvent(TestEventArgs(20)) - self.assertTrue(handler.value == 10) + ob.PublicEvent -= handler + assert handler.value == 10 - def testManagedInstanceMethodHandler(self): - """Test managed instance method handlers.""" - object = EventTest() + ob.OnPublicEvent(EventArgsTest(20)) + assert handler.value == 10 - object.PublicEvent += object.GenericHandler - self.assertTrue(object.value == 0) - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(object.value == 10) +def test_static_method_handler(): + """Test static method handlers.""" + ob = EventTest() + handler = StaticMethodHandler() + StaticMethodHandler.value = None - object.PublicEvent -= object.GenericHandler - self.assertTrue(object.value == 10) + ob.PublicEvent += handler.handler + assert handler.value is None - object.OnPublicEvent(TestEventArgs(20)) - self.assertTrue(object.value == 10) + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 10 - def testManagedStaticMethodHandler(self): - """Test managed static method handlers.""" - object = EventTest() - EventTest.s_value = 0 + ob.PublicEvent -= handler.handler + assert handler.value == 10 - object.PublicEvent += object.StaticHandler - self.assertTrue(EventTest.s_value == 0) + ob.OnPublicEvent(EventArgsTest(20)) + assert handler.value == 10 - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(EventTest.s_value == 10) - object.PublicEvent -= object.StaticHandler - self.assertTrue(EventTest.s_value == 10) +def test_class_method_handler(): + """Test class method handlers.""" + ob = EventTest() + handler = ClassMethodHandler() + ClassMethodHandler.value = None - object.OnPublicEvent(TestEventArgs(20)) - self.assertTrue(EventTest.s_value == 10) + ob.PublicEvent += handler.handler + assert handler.value is None - def testUnboundMethodHandler(self): - """Test failure mode for unbound method handlers.""" - object = EventTest() - object.PublicEvent += GenericHandler.handler - try: - object.OnPublicEvent(TestEventArgs(10)) - except TypeError: - object.PublicEvent -= GenericHandler.handler - return + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 10 - raise TypeError("should have raised a TypeError") + ob.PublicEvent -= handler.handler + assert handler.value == 10 - def testFunctionHandler(self): - """Test function handlers.""" - object = EventTest() - dict = {'value': None} + ob.OnPublicEvent(EventArgsTest(20)) + assert handler.value == 10 - def handler(sender, args, dict=dict): - dict['value'] = args.value - object.PublicEvent += handler - self.assertTrue(dict['value'] == None) +def test_managed_instance_method_handler(): + """Test managed instance method handlers.""" + ob = EventTest() - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(dict['value'] == 10) + ob.PublicEvent += ob.GenericHandler + assert ob.value == 0 - object.PublicEvent -= handler - self.assertTrue(dict['value'] == 10) + ob.OnPublicEvent(EventArgsTest(10)) + assert ob.value == 10 - object.OnPublicEvent(TestEventArgs(20)) - self.assertTrue(dict['value'] == 10) + ob.PublicEvent -= ob.GenericHandler + assert ob.value == 10 - def testAddNonCallableHandler(self): - """Test handling of attempts to add non-callable handlers.""" + ob.OnPublicEvent(EventArgsTest(20)) + assert ob.value == 10 - def test(): - object = EventTest() - object.PublicEvent += 10 - self.assertRaises(TypeError, test) +def test_managed_static_method_handler(): + """Test managed static method handlers.""" + ob = EventTest() + EventTest.s_value = 0 - def test(): - object = EventTest() - object.PublicEvent += "spam" + ob.PublicEvent += ob.StaticHandler + assert EventTest.s_value == 0 - self.assertRaises(TypeError, test) + ob.OnPublicEvent(EventArgsTest(10)) + assert EventTest.s_value == 10 - def test(): - class spam: - pass + ob.PublicEvent -= ob.StaticHandler + assert EventTest.s_value == 10 - object = EventTest() - object.PublicEvent += spam() + ob.OnPublicEvent(EventArgsTest(20)) + assert EventTest.s_value == 10 - self.assertRaises(TypeError, test) - def testRemoveMultipleHandlers(self): - """Test removing multiple instances of the same handler.""" - object = EventTest() - handler = MultipleHandler() +def test_unbound_method_handler(): + """Test failure mode for unbound method handlers.""" + ob = EventTest() + ob.PublicEvent += GenericHandler.handler - h1 = handler.handler - object.PublicEvent += h1 + with pytest.raises(TypeError): + ob.OnPublicEvent(EventArgsTest(10)) - h2 = handler.handler - object.PublicEvent += h2 + ob.PublicEvent -= GenericHandler.handler - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 20) - object.PublicEvent -= h1 +def test_function_handler(): + """Test function handlers.""" + ob = EventTest() + dict_ = {'value': None} - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 30) + def handler(sender, args, dict_=dict_): + dict_['value'] = args.value - object.PublicEvent -= h2 + ob.PublicEvent += handler + assert dict_['value'] is None - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 30) + ob.OnPublicEvent(EventArgsTest(10)) + assert dict_['value'] == 10 - # try again, removing in a different order. + ob.PublicEvent -= handler + assert dict_['value'] == 10 - object = EventTest() - handler = MultipleHandler() + ob.OnPublicEvent(EventArgsTest(20)) + assert dict_['value'] == 10 - h1 = handler.handler - object.PublicEvent += h1 - h2 = handler.handler - object.PublicEvent += h2 +def test_add_non_callable_handler(): + """Test handling of attempts to add non-callable handlers.""" - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 20) + with pytest.raises(TypeError): + ob = EventTest() + ob.PublicEvent += 10 - object.PublicEvent -= h2 + with pytest.raises(TypeError): + ob = EventTest() + ob.PublicEvent += "spam" - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 30) + with pytest.raises(TypeError): + class Spam(object): + pass - object.PublicEvent -= h1 + ob = EventTest() + ob.PublicEvent += Spam() - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 30) - def testRemoveMultipleStaticHandlers(self): - """Test removing multiple instances of a static handler.""" - object = EventTest() - handler = MultipleHandler() +def test_remove_multiple_handlers(): + """Test removing multiple instances of the same handler.""" + ob = EventTest() + handler = MultipleHandler() - h1 = handler.handler - object.PublicStaticEvent += h1 + h1 = handler.handler + ob.PublicEvent += h1 - h2 = handler.handler - object.PublicStaticEvent += h2 + h2 = handler.handler + ob.PublicEvent += h2 - object.OnPublicStaticEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 20) + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 20 - object.PublicStaticEvent -= h1 + ob.PublicEvent -= h1 - object.OnPublicStaticEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 30) + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 30 - object.PublicStaticEvent -= h2 + ob.PublicEvent -= h2 - object.OnPublicStaticEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 30) + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 30 - # try again, removing in a different order. + # try again, removing in a different order. - object = EventTest() - handler = MultipleHandler() + ob = EventTest() + handler = MultipleHandler() - h1 = handler.handler - object.PublicStaticEvent += h1 + h1 = handler.handler + ob.PublicEvent += h1 - h2 = handler.handler - object.PublicStaticEvent += h2 + h2 = handler.handler + ob.PublicEvent += h2 - object.OnPublicStaticEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 20) + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 20 - object.PublicStaticEvent -= h2 + ob.PublicEvent -= h2 - object.OnPublicStaticEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 30) + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 30 - object.PublicStaticEvent -= h1 + ob.PublicEvent -= h1 - object.OnPublicStaticEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 30) + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 30 - def testRandomMultipleHandlers(self): - """Test random subscribe / unsubscribe of the same handlers.""" - import random - object = EventTest() - handler = MultipleHandler() - handler2 = MultipleHandler() - object.PublicEvent += handler2.handler - object.PublicEvent += handler2.handler +def test_remove_multiple_static_handlers(): + """Test removing multiple instances of a static handler.""" + ob = EventTest() + handler = MultipleHandler() - handlers = [] - for i in range(30): - method = handler.handler - object.PublicEvent += method - handlers.append(method) + h1 = handler.handler + ob.PublicStaticEvent += h1 - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 300) - self.assertTrue(handler2.value == 20) - handler.value = 0 - handler2.value = 0 + h2 = handler.handler + ob.PublicStaticEvent += h2 - for i in range(30): - item = random.choice(handlers) - handlers.remove(item) - object.PublicEvent -= item - handler.value = 0 - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == (len(handlers) * 10)) - self.assertTrue(handler2.value == ((i + 1) * 20)) + ob.OnPublicStaticEvent(EventArgsTest(10)) + assert handler.value == 20 - handler2.value = 0 - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler2.value == 20) + ob.PublicStaticEvent -= h1 - object.PublicEvent -= handler2.handler + ob.OnPublicStaticEvent(EventArgsTest(10)) + assert handler.value == 30 - handler2.value = 0 - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler2.value == 10) + ob.PublicStaticEvent -= h2 - object.PublicEvent -= handler2.handler + ob.OnPublicStaticEvent(EventArgsTest(10)) + assert handler.value == 30 - handler2.value = 0 - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler2.value == 0) + # try again, removing in a different order. - def testRemoveInternalCallHandler(self): - """Test remove on an event sink implemented w/internalcall.""" - object = EventTest() + ob = EventTest() + handler = MultipleHandler() - def h(sender, args): - pass + h1 = handler.handler + ob.PublicStaticEvent += h1 - object.PublicEvent += h - object.PublicEvent -= h + h2 = handler.handler + ob.PublicStaticEvent += h2 - def testRemoveUnknownHandler(self): - """Test removing an event handler that was never added.""" + ob.OnPublicStaticEvent(EventArgsTest(10)) + assert handler.value == 20 - def test(): - object = EventTest() - handler = GenericHandler() + ob.PublicStaticEvent -= h2 - object.PublicEvent -= handler.handler + ob.OnPublicStaticEvent(EventArgsTest(10)) + assert handler.value == 30 - self.assertRaises(ValueError, test) + ob.PublicStaticEvent -= h1 - def testHandlerCallbackFailure(self): - """Test failure mode for inappropriate handlers.""" + ob.OnPublicStaticEvent(EventArgsTest(10)) + assert handler.value == 30 - class BadHandler: - def handler(self, one): - return 'too many' - object = EventTest() - handler = BadHandler() +def test_random_multiple_handlers(): + """Test random subscribe / unsubscribe of the same handlers.""" + import random + ob = EventTest() + handler = MultipleHandler() + handler2 = MultipleHandler() - def test(): - object.PublicEvent += handler.handler - object.OnPublicEvent(TestEventArgs(10)) + ob.PublicEvent += handler2.handler + ob.PublicEvent += handler2.handler - self.assertRaises(TypeError, test) + handlers = [] + for _ in range(30): + method = handler.handler + ob.PublicEvent += method + handlers.append(method) - object.PublicEvent -= handler.handler + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 300 + assert handler2.value == 20 + handler.value = 0 + handler2.value = 0 - class BadHandler: - def handler(self, one, two, three, four, five): - return 'not enough' + for i in range(30): + item = random.choice(handlers) + handlers.remove(item) + ob.PublicEvent -= item + handler.value = 0 + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == (len(handlers) * 10) + assert handler2.value == ((i + 1) * 20) - object = EventTest() - handler = BadHandler() + handler2.value = 0 + ob.OnPublicEvent(EventArgsTest(10)) + assert handler2.value == 20 - def test(): - object.PublicEvent += handler.handler - object.OnPublicEvent(TestEventArgs(10)) + ob.PublicEvent -= handler2.handler - self.assertRaises(TypeError, test) + handler2.value = 0 + ob.OnPublicEvent(EventArgsTest(10)) + assert handler2.value == 10 - object.PublicEvent -= handler.handler + ob.PublicEvent -= handler2.handler - def testIncorrectInvokation(self): - """Test incorrect invokation of events.""" - object = EventTest() + handler2.value = 0 + ob.OnPublicEvent(EventArgsTest(10)) + assert handler2.value == 0 - handler = GenericHandler() - object.PublicEvent += handler.handler - def test(): - object.OnPublicEvent() +def test_remove_internal_call_handler(): + """Test remove on an event sink implemented w/internalcall.""" + ob = EventTest() - self.assertRaises(TypeError, test) + def h(sender, args): + pass - def test(): - object.OnPublicEvent(32) + ob.PublicEvent += h + ob.PublicEvent -= h - self.assertRaises(TypeError, test) - object.PublicEvent -= handler.handler +def test_remove_unknown_handler(): + """Test removing an event handler that was never added.""" - def testExplicitCLSEventRegistration(self): - """Test explicit CLS event registration.""" - object = EventTest() + with pytest.raises(ValueError): + ob = EventTest() handler = GenericHandler() - delegate = TestEventHandler(handler.handler) - object.add_PublicEvent(delegate) - self.assertTrue(handler.value == None) - - object.OnPublicEvent(TestEventArgs(10)) - self.assertTrue(handler.value == 10) - - object.remove_PublicEvent(delegate) - self.assertTrue(handler.value == 10) + ob.PublicEvent -= handler.handler - object.OnPublicEvent(TestEventArgs(20)) - self.assertTrue(handler.value == 10) - def testImplicitCLSEventRegistration(self): - """Test implicit CLS event registration.""" +def test_handler_callback_failure(): + """Test failure mode for inappropriate handlers.""" - def test(): - object = EventTest() - handler = GenericHandler() - object.add_PublicEvent(handler.handler) + class BadHandler(object): + def handler(self, one): + return 'too many' - self.assertRaises(TypeError, test) + ob = EventTest() + handler = BadHandler() - def testEventDescriptorAbuse(self): - """Test event descriptor abuse.""" + with pytest.raises(TypeError): + ob.PublicEvent += handler.handler + ob.OnPublicEvent(EventArgsTest(10)) - def test(): - del EventTest.PublicEvent + ob.PublicEvent -= handler.handler - self.assertRaises(TypeError, test) + class BadHandler(object): + def handler(self, one, two, three, four, five): + return 'not enough' - def test(): - del EventTest.__dict__['PublicEvent'] + ob = EventTest() + handler = BadHandler() - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob.PublicEvent += handler.handler + ob.OnPublicEvent(EventArgsTest(10)) - desc = EventTest.__dict__['PublicEvent'] + ob.PublicEvent -= handler.handler - def test(): - desc.__get__(0, 0) - self.assertRaises(TypeError, test) +def test_incorrect_invokation(): + """Test incorrect invocation of events.""" + ob = EventTest() - def test(): - desc.__set__(0, 0) + handler = GenericHandler() + ob.PublicEvent += handler.handler - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob.OnPublicEvent() - def test(): - object = EventTest() - object.PublicEvent = 0 + with pytest.raises(TypeError): + ob.OnPublicEvent(32) - self.assertRaises(TypeError, test) + ob.PublicEvent -= handler.handler - def test(): - EventTest.PublicStaticEvent = 0 - self.assertRaises(TypeError, test) +def test_explicit_cls_event_registration(): + """Test explicit CLS event registration.""" + from Python.Test import EventHandlerTest + ob = EventTest() + handler = GenericHandler() -class GenericHandler: - """A generic handler to test event callbacks.""" + delegate = EventHandlerTest(handler.handler) + ob.add_PublicEvent(delegate) + assert handler.value is None - def __init__(self): - self.value = None + ob.OnPublicEvent(EventArgsTest(10)) + assert handler.value == 10 - def handler(self, sender, args): - self.value = args.value + ob.remove_PublicEvent(delegate) + assert handler.value == 10 + ob.OnPublicEvent(EventArgsTest(20)) + assert handler.value == 10 -class VariableArgsHandler: - """A variable args handler to test event callbacks.""" - def __init__(self): - self.value = None - - def handler(self, *args): - ob, eventargs = args - self.value = eventargs.value - - -class CallableHandler: - """A callable handler to test event callbacks.""" - - def __init__(self): - self.value = None - - def __call__(self, sender, args): - self.value = args.value - - -class VarCallableHandler: - """A variable args callable handler to test event callbacks.""" - - def __init__(self): - self.value = None - - def __call__(self, *args): - ob, eventargs = args - self.value = eventargs.value - - -class StaticMethodHandler(object): - """A static method handler to test event callbacks.""" - - value = None - - def handler(sender, args): - StaticMethodHandler.value = args.value - - handler = staticmethod(handler) - - -class ClassMethodHandler(object): - """A class method handler to test event callbacks.""" - - value = None - - def handler(cls, sender, args): - cls.value = args.value - - handler = classmethod(handler) +def test_implicit_cls_event_registration(): + """Test implicit CLS event registration.""" + with pytest.raises(TypeError): + ob = EventTest() + handler = GenericHandler() + ob.add_PublicEvent(handler.handler) -class MultipleHandler: - """A generic handler to test multiple callbacks.""" - def __init__(self): - self.value = 0 +def test_event_descriptor_abuse(): + """Test event descriptor abuse.""" - def handler(self, sender, args): - self.value += args.value + with pytest.raises(TypeError): + del EventTest.PublicEvent + with pytest.raises(TypeError): + del EventTest.__dict__['PublicEvent'] -def test_suite(): - return unittest.makeSuite(EventTests) + desc = EventTest.__dict__['PublicEvent'] + with pytest.raises(TypeError): + desc.__get__(0, 0) -def main(): - unittest.TextTestRunner().run(test_suite()) + with pytest.raises(TypeError): + desc.__set__(0, 0) + with pytest.raises(TypeError): + ob = EventTest() + ob.PublicEvent = 0 -if __name__ == '__main__': - main() + with pytest.raises(TypeError): + EventTest.PublicStaticEvent = 0 diff --git a/src/tests/test_exceptions.py b/src/tests/test_exceptions.py index eedf2aa61..f47209f6d 100644 --- a/src/tests/test_exceptions.py +++ b/src/tests/test_exceptions.py @@ -1,379 +1,347 @@ -import sys, os, string, unittest, types +# -*- coding: utf-8 -*- + +"""Test exception support.""" + +import sys + import System -import six +import pytest + +from ._compat import PY2, PY3, pickle, text_type + + +def test_unified_exception_semantics(): + """Test unified exception semantics.""" + e = System.Exception('Something bad happened') + assert isinstance(e, Exception) + assert isinstance(e, System.Exception) + + +def test_standard_exception_attributes(): + """Test accessing standard exception attributes.""" + from System import OverflowException + from Python.Test import ExceptionTest + + e = ExceptionTest.GetExplicitException() + assert isinstance(e, OverflowException) + + assert e.Message == 'error' + + e.Source = 'Test Suite' + assert e.Source == 'Test Suite' + + v = e.ToString() + assert len(v) > 0 + + +def test_extended_exception_attributes(): + """Test accessing extended exception attributes.""" + from Python.Test import ExceptionTest, ExtendedException + from System import OverflowException + + e = ExceptionTest.GetExtendedException() + assert isinstance(e, ExtendedException) + assert isinstance(e, OverflowException) + assert isinstance(e, System.Exception) + + assert e.Message == 'error' + + e.Source = 'Test Suite' + assert e.Source == 'Test Suite' + + v = e.ToString() + assert len(v) > 0 + + assert e.ExtraProperty == 'extra' + e.ExtraProperty = 'changed' + assert e.ExtraProperty == 'changed' + + assert e.GetExtraInfo() == 'changed' + + +def test_raise_class_exception(): + """Test class exception propagation.""" + from System import NullReferenceException + + with pytest.raises(NullReferenceException) as cm: + raise NullReferenceException + + exc = cm.value + assert isinstance(exc, NullReferenceException) + + +def test_exc_info(): + """Test class exception propagation. + Behavior of exc_info changed in Py3. Refactoring its test""" + from System import NullReferenceException + try: + raise NullReferenceException("message") + except Exception as exc: + type_, value, tb = sys.exc_info() + assert type_ is NullReferenceException + assert value.Message == "message" + assert exc.Message == "message" + # FIXME: Lower-case message isn't implemented + # self.assertTrue(exc.message == "message") + assert value is exc + + +def test_raise_class_exception_with_value(): + """Test class exception propagation with associated value.""" + from System import NullReferenceException + + with pytest.raises(NullReferenceException) as cm: + raise NullReferenceException('Aiiieee!') + + exc = cm.value + assert isinstance(exc, NullReferenceException) + assert exc.Message == 'Aiiieee!' + + +def test_raise_instance_exception(): + """Test instance exception propagation.""" + from System import NullReferenceException + + with pytest.raises(NullReferenceException) as cm: + raise NullReferenceException() + + exc = cm.value + assert isinstance(exc, NullReferenceException) + assert len(exc.Message) > 0 + + +def test_raise_instance_exception_with_args(): + """Test instance exception propagation with args.""" + from System import NullReferenceException + + with pytest.raises(NullReferenceException) as cm: + raise NullReferenceException("Aiiieee!") + + exc = cm.value + assert isinstance(exc, NullReferenceException) + assert exc.Message == 'Aiiieee!' + + +def test_managed_exception_propagation(): + """Test propagation of exceptions raised in managed code.""" + from System import Decimal, OverflowException + + with pytest.raises(OverflowException): + Decimal.ToInt64(Decimal.MaxValue) + + +def test_managed_exception_conversion(): + """Test conversion of managed exceptions.""" + from System import OverflowException + from Python.Test import ExceptionTest + + e = ExceptionTest.GetBaseException() + assert isinstance(e, System.Exception) + + e = ExceptionTest.GetExplicitException() + assert isinstance(e, OverflowException) + assert isinstance(e, System.Exception) + + e = ExceptionTest.GetWidenedException() + assert isinstance(e, OverflowException) + assert isinstance(e, System.Exception) + + v = ExceptionTest.SetBaseException(System.Exception('error')) + assert v + + v = ExceptionTest.SetExplicitException(OverflowException('error')) + assert v + + v = ExceptionTest.SetWidenedException(OverflowException('error')) + assert v + + +def test_catch_exception_from_managed_method(): + """Test catching an exception from a managed method.""" + from Python.Test import ExceptionTest + from System import OverflowException + + with pytest.raises(OverflowException) as cm: + ExceptionTest().ThrowException() + + e = cm.value + assert isinstance(e, OverflowException) + + +def test_catch_exception_from_managed_property(): + """Test catching an exception from a managed property.""" + from Python.Test import ExceptionTest + from System import OverflowException + + with pytest.raises(OverflowException) as cm: + _ = ExceptionTest().ThrowProperty + + e = cm.value + assert isinstance(e, OverflowException) + + with pytest.raises(OverflowException) as cm: + ExceptionTest().ThrowProperty = 1 + + e = cm.value + assert isinstance(e, OverflowException) + + +def test_catch_exception_managed_class(): + """Test catching the managed class of an exception.""" + from System import OverflowException + + with pytest.raises(OverflowException): + raise OverflowException('overflow') + + +def test_catch_exception_python_class(): + """Test catching the python class of an exception.""" + from System import OverflowException + + with pytest.raises(Exception): + raise OverflowException('overflow') + -if six.PY3: - unicode = str +def test_catch_exception_base_class(): + """Test catching the base of an exception.""" + from System import OverflowException, ArithmeticException + with pytest.raises(ArithmeticException): + raise OverflowException('overflow') -class ExceptionTests(unittest.TestCase): - """Test exception support.""" - def testUnifiedExceptionSemantics(self): - """Test unified exception semantics.""" - from System import Exception, Object +def test_catch_exception_nested_base_class(): + """Test catching the nested base of an exception.""" + from System import OverflowException, SystemException - e = Exception('Something bad happened') - if not six.PY3: - import exceptions - self.assertTrue(isinstance(e, exceptions.Exception)) - self.assertTrue(isinstance(e, Exception)) + with pytest.raises(SystemException): + raise OverflowException('overflow') - def testStandardExceptionAttributes(self): - """Test accessing standard exception attributes.""" - from System import OverflowException - from Python.Test import ExceptionTest - e = ExceptionTest.GetExplicitException() - self.assertTrue(isinstance(e, OverflowException)) +def test_catch_exception_with_assignment(): + """Test catching an exception with assignment.""" + from System import OverflowException - self.assertTrue(e.Message == 'error') + with pytest.raises(OverflowException) as cm: + raise OverflowException('overflow') - e.Source = 'Test Suite' - self.assertTrue(e.Source == 'Test Suite') + e = cm.value + assert isinstance(e, OverflowException) - v = e.ToString() - self.assertTrue(len(v) > 0) - def testExtendedExceptionAttributes(self): - """Test accessing extended exception attributes.""" - from Python.Test import ExceptionTest, ExtendedException - from System import Exception, OverflowException +def test_catch_exception_unqualified(): + """Test catching an unqualified exception.""" + from System import OverflowException - e = ExceptionTest.GetExtendedException() - self.assertTrue(isinstance(e, ExtendedException)) - self.assertTrue(isinstance(e, OverflowException)) - self.assertTrue(isinstance(e, Exception)) + try: + raise OverflowException('overflow') + except: + pass + else: + self.fail("failed to catch unqualified exception") - self.assertTrue(e.Message == 'error') - e.Source = 'Test Suite' - self.assertTrue(e.Source == 'Test Suite') +def test_catch_baseexception(): + """Test catching an unqualified exception with BaseException.""" + from System import OverflowException - v = e.ToString() - self.assertTrue(len(v) > 0) + with pytest.raises(BaseException): + raise OverflowException('overflow') - self.assertTrue(e.ExtraProperty == 'extra') - e.ExtraProperty = 'changed' - self.assertTrue(e.ExtraProperty == 'changed') - self.assertTrue(e.GetExtraInfo() == 'changed') +def test_apparent_module_of_exception(): + """Test the apparent module of an exception.""" + from System import OverflowException - def testRaiseClassException(self): - """Test class exception propagation.""" - from System import NullReferenceException + assert System.Exception.__module__ == 'System' + assert OverflowException.__module__ == 'System' - def test(): - raise NullReferenceException - self.assertRaises(NullReferenceException, test) +def test_str_of_exception(): + """Test the str() representation of an exception.""" + from System import NullReferenceException, Convert, FormatException - try: - raise NullReferenceException - except: - type, value, tb = sys.exc_info() - self.assertTrue(type is NullReferenceException) - self.assertTrue(isinstance(value, NullReferenceException)) + e = NullReferenceException('') + assert str(e) == '' - def testRaiseClassExceptionWithValue(self): - """Test class exception propagation with associated value.""" - from System import NullReferenceException + e = NullReferenceException('Something bad happened') + assert str(e).startswith('Something bad happened') - def test(): - raise NullReferenceException('Aiiieee!') + with pytest.raises(FormatException) as cm: + Convert.ToDateTime('this will fail') - self.assertRaises(NullReferenceException, test) + e = cm.value + # fix for international installation + msg = text_type(e).encode("utf8") + fnd = text_type('System.Convert.ToDateTime').encode("utf8") + assert msg.find(fnd) > -1, msg - try: - raise NullReferenceException('Aiiieee!') - except: - type, value, tb = sys.exc_info() - self.assertTrue(type is NullReferenceException) - self.assertTrue(isinstance(value, NullReferenceException)) - self.assertTrue(value.Message == 'Aiiieee!') - def testRaiseInstanceException(self): - """Test instance exception propagation.""" - from System import NullReferenceException +def test_python_compat_of_managed_exceptions(): + """Test managed exceptions compatible with Python's implementation""" + from System import OverflowException + msg = "Simple message" - def test(): - raise NullReferenceException() + e = OverflowException(msg) + assert str(e) == msg + assert text_type(e) == msg - self.assertRaises(NullReferenceException, test) + assert e.args == (msg,) + assert isinstance(e.args, tuple) + if PY3: + assert repr(e) == "OverflowException('Simple message',)" + elif PY2: + assert repr(e) == "OverflowException(u'Simple message',)" - try: - raise NullReferenceException() - except: - type, value, tb = sys.exc_info() - self.assertTrue(type is NullReferenceException) - self.assertTrue(isinstance(value, NullReferenceException)) - self.assertTrue(len(value.Message) > 0) - def testRaiseInstanceExceptionWithArgs(self): - """Test instance exception propagation with args.""" - from System import NullReferenceException +def test_exception_is_instance_of_system_object(): + """Test behavior of isinstance(, System.Object).""" + # This is an anti-test, in that this is a caveat of the current + # implementation. Because exceptions are not allowed to be new-style + # classes, we wrap managed exceptions in a general-purpose old-style + # class that delegates to the wrapped object. This makes _almost_ + # everything work as expected, except that an isinstance check against + # CLR.System.Object will fail for a managed exception (because a new + # style class cannot appear in the __bases__ of an old-style class + # without causing a crash in the CPython interpreter). This test is + # here mainly to remind me to update the caveat in the documentation + # one day when when exceptions can be new-style classes. - def test(): - raise NullReferenceException("Aiieeee!") + # This behavior is now over-shadowed by the implementation of + # __instancecheck__ (i.e., overloading isinstance), so for all Python + # version >= 2.6 we expect isinstance(, Object) to + # be true, even though it does not really subclass Object. + from System import OverflowException, Object - self.assertRaises(NullReferenceException, test) + o = OverflowException('error') - try: - raise NullReferenceException('Aiiieee!') - except: - type, value, tb = sys.exc_info() - self.assertTrue(type is NullReferenceException) - self.assertTrue(isinstance(value, NullReferenceException)) - self.assertTrue(value.Message == 'Aiiieee!') + if sys.version_info >= (2, 6): + assert isinstance(o, Object) + else: + assert not isinstance(o, Object) - def testManagedExceptionPropagation(self): - """Test propagation of exceptions raised in managed code.""" - from System import Decimal, OverflowException - def test(): - l = Decimal.ToInt64(Decimal.MaxValue) +def test_pickling_exceptions(): + exc = System.Exception("test") + dumped = pickle.dumps(exc) + loaded = pickle.loads(dumped) - self.assertRaises(OverflowException, test) + assert exc.args == loaded.args - def testManagedExceptionConversion(self): - """Test conversion of managed exceptions.""" - from System import Exception, OverflowException - from Python.Test import ExceptionTest - e = ExceptionTest.GetBaseException() - self.assertTrue(isinstance(e, Exception)) +@pytest.mark.skipif(PY2, reason="__cause__ isn't implemented in PY2") +def test_chained_exceptions(): + from Python.Test import ExceptionTest - e = ExceptionTest.GetExplicitException() - self.assertTrue(isinstance(e, OverflowException)) - self.assertTrue(isinstance(e, Exception)) + with pytest.raises(Exception) as cm: + ExceptionTest.ThrowChainedExceptions() - e = ExceptionTest.GetWidenedException() - self.assertTrue(isinstance(e, OverflowException)) - self.assertTrue(isinstance(e, Exception)) - - v = ExceptionTest.SetBaseException(Exception('error')) - self.assertTrue(v) - - v = ExceptionTest.SetExplicitException(OverflowException('error')) - self.assertTrue(v) + exc = cm.value - v = ExceptionTest.SetWidenedException(OverflowException('error')) - self.assertTrue(v) - - def testCatchExceptionFromManagedMethod(self): - """Test catching an exception from a managed method.""" - from Python.Test import ExceptionTest - from System import OverflowException - - try: - ExceptionTest().ThrowException() - except OverflowException: - e = sys.exc_info()[1] - self.assertTrue(isinstance(e, OverflowException)) - return - - raise SystemError('failed to catch exception from managed method') - - def testCatchExceptionFromManagedProperty(self): - """Test catching an exception from a managed property.""" - from Python.Test import ExceptionTest - from System import OverflowException - - try: - v = ExceptionTest().ThrowProperty - except OverflowException: - e = sys.exc_info()[1] - self.assertTrue(isinstance(e, OverflowException)) - return - - try: - ExceptionTest().ThrowProperty = 1 - except OverflowException: - e = sys.exc_info()[1] - self.assertTrue(isinstance(e, OverflowException)) - return - - raise SystemError('failed to catch exception from managed property') - - def testCatchExceptionManagedClass(self): - """Test catching the managed class of an exception.""" - from System import OverflowException - - try: - raise OverflowException('overflow') - except OverflowException: - return - - raise SystemError('failed to catch managed class exception') - - def testCatchExceptionPythonClass(self): - """Test catching the python class of an exception.""" - from System import OverflowException - if six.PY3: - from builtins import Exception - else: - from exceptions import Exception - - try: - raise OverflowException('overflow') - except Exception: - return - - raise SystemError('failed to catch python class exception') - - def testCatchExceptionBaseClass(self): - """Test catching the base of an exception.""" - from System import OverflowException, ArithmeticException - - try: - raise OverflowException('overflow') - except ArithmeticException: - return - - raise SystemError('failed to catch base exception') - - def testCatchExceptionNestedBaseClass(self): - """Test catching the nested base of an exception.""" - from System import OverflowException, SystemException - - try: - raise OverflowException('overflow') - except SystemException: - return - - raise SystemError('failed to catch nested base exception') - - def testCatchExceptionWithAssignment(self): - """Test catching an exception with assignment.""" - from System import OverflowException - - try: - raise OverflowException('overflow') - except OverflowException: - e = sys.exc_info()[1] - self.assertTrue(isinstance(e, OverflowException)) - - def testCatchExceptionUnqualified(self): - """Test catching an unqualified exception.""" - from System import OverflowException - - try: - raise OverflowException('overflow') - except: - return - - raise SystemError('failed to catch unqualified exception') - - def testApparentModuleOfException(self): - """Test the apparent module of an exception.""" - from System import Exception, OverflowException - - self.assertTrue(Exception.__module__ == 'System') - self.assertTrue(OverflowException.__module__ == 'System') - - def testStrOfException(self): - """Test the str() representation of an exception.""" - from System import NullReferenceException - from System import Convert, FormatException - e = NullReferenceException('') - self.assertEqual(str(e), '') - - e = NullReferenceException('Something bad happened') - self.assertTrue(str(e).startswith('Something bad happened')) - - try: - Convert.ToDateTime('this will fail') - except FormatException: - e = sys.exc_info()[1] - msg = unicode(e).encode("utf8") # fix for international installation - self.assertTrue(msg.find(unicode('System.Convert.ToDateTime').encode("utf8")) > -1, msg) - - def testPythonCompatOfManagedExceptions(self): - """Test if managed exceptions are compatible with Python's implementation - """ - from System import OverflowException - msg = "A simple message" - - e = OverflowException(msg) - self.assertEqual(str(e), msg) - self.assertEqual(unicode(e), msg) - - self.assertEqual(e.args, (msg,)) - self.assertTrue(isinstance(e.args, tuple)) - if six.PY2: - self.assertEqual(repr(e), "OverflowException(u'A simple message',)") - else: - self.assertEqual(repr(e), "OverflowException('A simple message',)") - - def testExceptionIsInstanceOfSystemObject(self): - """Test behavior of isinstance(, System.Object).""" - # This is an anti-test, in that this is a caveat of the current - # implementation. Because exceptions are not allowed to be new-style - # classes, we wrap managed exceptions in a general-purpose old-style - # class that delegates to the wrapped object. This makes _almost_ - # everything work as expected, except that an isinstance check against - # CLR.System.Object will fail for a managed exception (because a new - # style class cannot appear in the __bases__ of an old-style class - # without causing a crash in the CPython interpreter). This test is - # here mainly to remind me to update the caveat in the documentation - # one day when when exceptions can be new-style classes. - - # This behaviour is now over-shadowed by the implementation of - # __instancecheck__ (i.e., overloading isinstance), so for all Python - # version >= 2.6 we expect isinstance(, Object) to - # be true, even though it does not really subclass Object. - from System import OverflowException - from System import Object - - o = OverflowException('error') - - if sys.version_info >= (2, 6): - self.assertTrue(isinstance(o, Object)) - else: - self.assertFalse(isinstance(o, Object)) - - def testPicklingExceptions(self): - from System import Exception - try: - import cPickle as pickle - except ImportError: - import pickle - - exc = Exception("test") - dumped = pickle.dumps(exc) - loaded = pickle.loads(dumped) - - self.assertEqual(exc.args, loaded.args) - - def testChainedExceptions(self): - if six.PY3: - from Python.Test import ExceptionTest - - try: - ExceptionTest.ThrowChainedExceptions() - except Exception as exc: - msgs = [ - "Outer exception", - "Inner exception", - "Innermost exception" - ] - - for msg in msgs: - self.assertEqual(exc.Message, msg) - self.assertEqual(exc.__cause__, exc.InnerException) - exc = exc.__cause__ - - else: - self.fail("Test should raise an exception") - - -def test_suite(): - return unittest.makeSuite(ExceptionTests) - - -def main(): - unittest.TextTestRunner().run(test_suite()) - - -if __name__ == '__main__': - main() + msgs = ("Outer exception", + "Inner exception", + "Innermost exception",) + for msg in msgs: + assert exc.Message == msg + assert exc.__cause__ == exc.InnerException + exc = exc.__cause__ diff --git a/src/tests/test_field.py b/src/tests/test_field.py index d765e3888..d187de5d2 100644 --- a/src/tests/test_field.py +++ b/src/tests/test_field.py @@ -1,433 +1,392 @@ -import sys, os, string, unittest, types -from Python.Test import FieldTest -from Python.Test import ShortEnum -import System -import six - -if six.PY3: - IntType = int -else: - IntType = types.IntType - +# -*- coding: utf-8 -*- -class FieldTests(unittest.TestCase): - """Test CLR field support.""" +"""Test CLR field support.""" - def testPublicInstanceField(self): - """Test public instance fields.""" - object = FieldTest(); - self.assertTrue(object.PublicField == 0) - - object.PublicField = 1 - self.assertTrue(object.PublicField == 1) +import System +import pytest +from Python.Test import FieldTest - def test(): - del FieldTest().PublicField - self.assertRaises(TypeError, test) +def test_public_instance_field(): + """Test public instance fields.""" + ob = FieldTest() + assert ob.PublicField == 0 - def testPublicStaticField(self): - """Test public static fields.""" - object = FieldTest(); - self.assertTrue(FieldTest.PublicStaticField == 0) + ob.PublicField = 1 + assert ob.PublicField == 1 - FieldTest.PublicStaticField = 1 - self.assertTrue(FieldTest.PublicStaticField == 1) + with pytest.raises(TypeError): + del FieldTest().PublicField - self.assertTrue(object.PublicStaticField == 1) - object.PublicStaticField = 0 - self.assertTrue(object.PublicStaticField == 0) - def test(): - del FieldTest.PublicStaticField +def test_public_static_field(): + """Test public static fields.""" + ob = FieldTest() + assert FieldTest.PublicStaticField == 0 - self.assertRaises(TypeError, test) + FieldTest.PublicStaticField = 1 + assert FieldTest.PublicStaticField == 1 - def test(): - del FieldTest().PublicStaticField + assert ob.PublicStaticField == 1 + ob.PublicStaticField = 0 + assert ob.PublicStaticField == 0 - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + del FieldTest.PublicStaticField - def testProtectedInstanceField(self): - """Test protected instance fields.""" - object = FieldTest(); - self.assertTrue(object.ProtectedField == 0) + with pytest.raises(TypeError): + del FieldTest().PublicStaticField - object.ProtectedField = 1 - self.assertTrue(object.ProtectedField == 1) - def test(): - del FieldTest().ProtectedField +def test_protected_instance_field(): + """Test protected instance fields.""" + ob = FieldTest() + assert ob.ProtectedField == 0 - self.assertRaises(TypeError, test) + ob.ProtectedField = 1 + assert ob.ProtectedField == 1 - def testProtectedStaticField(self): - """Test protected static fields.""" - object = FieldTest(); - self.assertTrue(FieldTest.ProtectedStaticField == 0) + with pytest.raises(TypeError): + del FieldTest().ProtectedField - FieldTest.ProtectedStaticField = 1 - self.assertTrue(FieldTest.ProtectedStaticField == 1) - self.assertTrue(object.ProtectedStaticField == 1) - object.ProtectedStaticField = 0 - self.assertTrue(object.ProtectedStaticField == 0) +def test_protected_static_field(): + """Test protected static fields.""" + ob = FieldTest() + assert FieldTest.ProtectedStaticField == 0 - def test(): - del FieldTest.ProtectedStaticField + FieldTest.ProtectedStaticField = 1 + assert FieldTest.ProtectedStaticField == 1 - self.assertRaises(TypeError, test) + assert ob.ProtectedStaticField == 1 + ob.ProtectedStaticField = 0 + assert ob.ProtectedStaticField == 0 - def test(): - del FieldTest().ProtectedStaticField + with pytest.raises(TypeError): + del FieldTest.ProtectedStaticField - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + del FieldTest().ProtectedStaticField - def testReadOnlyInstanceField(self): - """Test readonly instance fields.""" - self.assertTrue(FieldTest().ReadOnlyField == 0) - def test(): - FieldTest().ReadOnlyField = 1 +def test_read_only_instance_field(): + """Test readonly instance fields.""" + assert FieldTest().ReadOnlyField == 0 - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + FieldTest().ReadOnlyField = 1 - def test(): - del FieldTest().ReadOnlyField + with pytest.raises(TypeError): + del FieldTest().ReadOnlyField - self.assertRaises(TypeError, test) - def testReadOnlyStaticField(self): - """Test readonly static fields.""" - object = FieldTest(); +def test_read_only_static_field(): + """Test readonly static fields.""" + ob = FieldTest() - self.assertTrue(FieldTest.ReadOnlyStaticField == 0) - self.assertTrue(object.ReadOnlyStaticField == 0) + assert FieldTest.ReadOnlyStaticField == 0 + assert ob.ReadOnlyStaticField == 0 - def test(): - FieldTest.ReadOnlyStaticField = 1 + with pytest.raises(TypeError): + FieldTest.ReadOnlyStaticField = 1 - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + FieldTest().ReadOnlyStaticField = 1 - def test(): - FieldTest().ReadOnlyStaticField = 1 + with pytest.raises(TypeError): + del FieldTest.ReadOnlyStaticField - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + del FieldTest().ReadOnlyStaticField - def test(): - del FieldTest.ReadOnlyStaticField - self.assertRaises(TypeError, test) +def test_constant_field(): + """Test const fields.""" + ob = FieldTest() - def test(): - del FieldTest().ReadOnlyStaticField + assert FieldTest.ConstField == 0 + assert ob.ConstField == 0 - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + FieldTest().ConstField = 1 - def testConstantField(self): - """Test const fields.""" - object = FieldTest(); + with pytest.raises(TypeError): + FieldTest.ConstField = 1 - self.assertTrue(FieldTest.ConstField == 0) - self.assertTrue(object.ConstField == 0) + with pytest.raises(TypeError): + del FieldTest().ConstField - def test(): - FieldTest().ConstField = 1 + with pytest.raises(TypeError): + del FieldTest.ConstField - self.assertRaises(TypeError, test) - def test(): - FieldTest.ConstField = 1 +def test_internal_field(): + """Test internal fields.""" - self.assertRaises(TypeError, test) + with pytest.raises(AttributeError): + _ = FieldTest().InternalField - def test(): - del FieldTest().ConstField + with pytest.raises(AttributeError): + _ = FieldTest().InternalStaticField - self.assertRaises(TypeError, test) + with pytest.raises(AttributeError): + _ = FieldTest.InternalStaticField - def test(): - del FieldTest.ConstField - self.assertRaises(TypeError, test) +def test_private_field(): + """Test private fields.""" - def testInternalField(self): - """Test internal fields.""" + with pytest.raises(AttributeError): + _ = FieldTest().PrivateField - def test(): - f = FieldTest().InternalField + with pytest.raises(AttributeError): + _ = FieldTest().PrivateStaticField - self.assertRaises(AttributeError, test) + with pytest.raises(AttributeError): + _ = FieldTest.PrivateStaticField - def test(): - f = FieldTest().InternalStaticField - self.assertRaises(AttributeError, test) +def test_field_descriptor_get_set(): + """Test field descriptor get / set.""" - def test(): - f = FieldTest.InternalStaticField + # This test ensures that setting an attribute implemented with + # a descriptor actually goes through the descriptor (rather than + # silently replacing the descriptor in the instance or type dict. - self.assertRaises(AttributeError, test) + ob = FieldTest() - def testPrivateField(self): - """Test private fields.""" + assert FieldTest.PublicStaticField == 0 + assert ob.PublicStaticField == 0 - def test(): - f = FieldTest().PrivateField + descriptor = FieldTest.__dict__['PublicStaticField'] + assert type(descriptor) != int - self.assertRaises(AttributeError, test) + ob.PublicStaticField = 0 + descriptor = FieldTest.__dict__['PublicStaticField'] + assert type(descriptor) != int - def test(): - f = FieldTest().PrivateStaticField + FieldTest.PublicStaticField = 0 + descriptor = FieldTest.__dict__['PublicStaticField'] + assert type(descriptor) != int - self.assertRaises(AttributeError, test) - def test(): - f = FieldTest.PrivateStaticField +def test_field_descriptor_wrong_type(): + """Test setting a field using a value of the wrong type.""" - self.assertRaises(AttributeError, test) + with pytest.raises(TypeError): + FieldTest().PublicField = "spam" - def testFieldDescriptorGetSet(self): - """Test field descriptor get / set.""" - # This test ensures that setting an attribute implemented with - # a descriptor actually goes through the descriptor (rather than - # silently replacing the descriptor in the instance or type dict. +def test_field_descriptor_abuse(): + """Test field descriptor abuse.""" + desc = FieldTest.__dict__['PublicField'] - object = FieldTest() + with pytest.raises(TypeError): + desc.__get__(0, 0) - self.assertTrue(FieldTest.PublicStaticField == 0) - self.assertTrue(object.PublicStaticField == 0) + with pytest.raises(TypeError): + desc.__set__(0, 0) - descriptor = FieldTest.__dict__['PublicStaticField'] - self.assertTrue(type(descriptor) != IntType) - object.PublicStaticField = 0 - descriptor = FieldTest.__dict__['PublicStaticField'] - self.assertTrue(type(descriptor) != IntType) +def test_boolean_field(): + """Test boolean fields.""" + # change this to true / false later for Python 2.3? + ob = FieldTest() + assert ob.BooleanField is False - FieldTest.PublicStaticField = 0 - descriptor = FieldTest.__dict__['PublicStaticField'] - self.assertTrue(type(descriptor) != IntType) + ob.BooleanField = True + assert ob.BooleanField is True - def testFieldDescriptorWrongType(self): - """Test setting a field using a value of the wrong type.""" + ob.BooleanField = False + assert ob.BooleanField is False - def test(): - FieldTest().PublicField = "spam" + ob.BooleanField = 1 + assert ob.BooleanField is True - self.assertRaises(TypeError, test) + ob.BooleanField = 0 + assert ob.BooleanField is False - def testFieldDescriptorAbuse(self): - """Test field descriptor abuse.""" - desc = FieldTest.__dict__['PublicField'] - def test(): - desc.__get__(0, 0) +def test_sbyte_field(): + """Test sbyte fields.""" + ob = FieldTest() + assert ob.SByteField == 0 - self.assertRaises(TypeError, test) + ob.SByteField = 1 + assert ob.SByteField == 1 - def test(): - desc.__set__(0, 0) - self.assertRaises(TypeError, test) +def test_byte_field(): + """Test byte fields.""" + ob = FieldTest() + assert ob.ByteField == 0 - def testBooleanField(self): - """Test boolean fields.""" - # change this to true / false later for Python 2.3? - object = FieldTest() - self.assertTrue(object.BooleanField == False) + ob.ByteField = 1 + assert ob.ByteField == 1 - object.BooleanField = True - self.assertTrue(object.BooleanField == True) - object.BooleanField = False - self.assertTrue(object.BooleanField == False) +def test_char_field(): + """Test char fields.""" + ob = FieldTest() + assert ob.CharField == u'A' + assert ob.CharField == 'A' - object.BooleanField = 1 - self.assertTrue(object.BooleanField == True) + ob.CharField = 'B' + assert ob.CharField == u'B' + assert ob.CharField == 'B' - object.BooleanField = 0 - self.assertTrue(object.BooleanField == False) + ob.CharField = u'C' + assert ob.CharField == u'C' + assert ob.CharField == 'C' - def testSByteField(self): - """Test sbyte fields.""" - object = FieldTest() - self.assertTrue(object.SByteField == 0) - object.SByteField = 1 - self.assertTrue(object.SByteField == 1) +def test_int16_field(): + """Test int16 fields.""" + ob = FieldTest() + assert ob.Int16Field == 0 - def testByteField(self): - """Test byte fields.""" - object = FieldTest() - self.assertTrue(object.ByteField == 0) + ob.Int16Field = 1 + assert ob.Int16Field == 1 - object.ByteField = 1 - self.assertTrue(object.ByteField == 1) - def testCharField(self): - """Test char fields.""" - object = FieldTest() - self.assertTrue(object.CharField == six.u('A')) - self.assertTrue(object.CharField == 'A') +def test_int32_field(): + """Test int32 fields.""" + ob = FieldTest() + assert ob.Int32Field == 0 - object.CharField = 'B' - self.assertTrue(object.CharField == six.u('B')) - self.assertTrue(object.CharField == 'B') + ob.Int32Field = 1 + assert ob.Int32Field == 1 - object.CharField = six.u('C') - self.assertTrue(object.CharField == six.u('C')) - self.assertTrue(object.CharField == 'C') - def testInt16Field(self): - """Test int16 fields.""" - object = FieldTest() - self.assertTrue(object.Int16Field == 0) +def test_int64_field(): + """Test int64 fields.""" + ob = FieldTest() + assert ob.Int64Field == 0 - object.Int16Field = 1 - self.assertTrue(object.Int16Field == 1) + ob.Int64Field = 1 + assert ob.Int64Field == 1 - def testInt32Field(self): - """Test int32 fields.""" - object = FieldTest() - self.assertTrue(object.Int32Field == 0) - object.Int32Field = 1 - self.assertTrue(object.Int32Field == 1) +def test_uint16_field(): + """Test uint16 fields.""" + ob = FieldTest() + assert ob.UInt16Field == 0 - def testInt64Field(self): - """Test int64 fields.""" - object = FieldTest() - self.assertTrue(object.Int64Field == 0) + ob.UInt16Field = 1 + assert ob.UInt16Field == 1 - object.Int64Field = 1 - self.assertTrue(object.Int64Field == 1) - def testUInt16Field(self): - """Test uint16 fields.""" - object = FieldTest() - self.assertTrue(object.UInt16Field == 0) +def test_uint32_field(): + """Test uint32 fields.""" + ob = FieldTest() + assert ob.UInt32Field == 0 - object.UInt16Field = 1 - self.assertTrue(object.UInt16Field == 1) + ob.UInt32Field = 1 + assert ob.UInt32Field == 1 - def testUInt32Field(self): - """Test uint32 fields.""" - object = FieldTest() - self.assertTrue(object.UInt32Field == 0) - object.UInt32Field = 1 - self.assertTrue(object.UInt32Field == 1) +def test_uint64_field(): + """Test uint64 fields.""" + ob = FieldTest() + assert ob.UInt64Field == 0 - def testUInt64Field(self): - """Test uint64 fields.""" - object = FieldTest() - self.assertTrue(object.UInt64Field == 0) + ob.UInt64Field = 1 + assert ob.UInt64Field == 1 - object.UInt64Field = 1 - self.assertTrue(object.UInt64Field == 1) - def testSingleField(self): - """Test single fields.""" - object = FieldTest() - self.assertTrue(object.SingleField == 0.0) +def test_single_field(): + """Test single fields.""" + ob = FieldTest() + assert ob.SingleField == 0.0 - object.SingleField = 1.1 - self.assertTrue(object.SingleField == 1.1) + ob.SingleField = 1.1 + assert ob.SingleField == 1.1 - def testDoubleField(self): - """Test double fields.""" - object = FieldTest() - self.assertTrue(object.DoubleField == 0.0) - object.DoubleField = 1.1 - self.assertTrue(object.DoubleField == 1.1) +def test_double_field(): + """Test double fields.""" + ob = FieldTest() + assert ob.DoubleField == 0.0 - def testDecimalField(self): - """Test decimal fields.""" - object = FieldTest() - self.assertTrue(object.DecimalField == System.Decimal(0)) + ob.DoubleField = 1.1 + assert ob.DoubleField == 1.1 - object.DecimalField = System.Decimal(1) - self.assertTrue(object.DecimalField == System.Decimal(1)) - def testStringField(self): - """Test string fields.""" - object = FieldTest() - self.assertTrue(object.StringField == "spam") +def test_decimal_field(): + """Test decimal fields.""" + ob = FieldTest() + assert ob.DecimalField == System.Decimal(0) - object.StringField = "eggs" - self.assertTrue(object.StringField == "eggs") + ob.DecimalField = System.Decimal(1) + assert ob.DecimalField == System.Decimal(1) - def testInterfaceField(self): - """Test interface fields.""" - from Python.Test import Spam, ISpam - object = FieldTest() +def test_string_field(): + """Test string fields.""" + ob = FieldTest() + assert ob.StringField == "spam" - self.assertTrue(ISpam(object.SpamField).GetValue() == "spam") - self.assertTrue(object.SpamField.GetValue() == "spam") + ob.StringField = "eggs" + assert ob.StringField == "eggs" - object.SpamField = Spam("eggs") - self.assertTrue(ISpam(object.SpamField).GetValue() == "eggs") - self.assertTrue(object.SpamField.GetValue() == "eggs") - def testObjectField(self): - """Test object fields.""" - object = FieldTest() - self.assertTrue(object.ObjectField == None) +def test_interface_field(): + """Test interface fields.""" + from Python.Test import Spam, ISpam - object.ObjectField = System.String("spam") - self.assertTrue(object.ObjectField == "spam") + ob = FieldTest() - object.ObjectField = System.Int32(1) - self.assertTrue(object.ObjectField == 1) + assert ISpam(ob.SpamField).GetValue() == "spam" + assert ob.SpamField.GetValue() == "spam" - object.ObjectField = None - self.assertTrue(object.ObjectField == None) + ob.SpamField = Spam("eggs") + assert ISpam(ob.SpamField).GetValue() == "eggs" + assert ob.SpamField.GetValue() == "eggs" - def testEnumField(self): - """Test enum fields.""" - object = FieldTest() - self.assertTrue(object.EnumField == ShortEnum.Zero) - object.EnumField = ShortEnum.One - self.assertTrue(object.EnumField == ShortEnum.One) +def test_object_field(): + """Test ob fields.""" + ob = FieldTest() + assert ob.ObjectField is None - def testNullableField(self): - """Test nullable fields.""" - object = FieldTest() + ob.ObjectField = System.String("spam") + assert ob.ObjectField == "spam" - object.StringField = None - self.assertTrue(object.StringField == None) + ob.ObjectField = System.Int32(1) + assert ob.ObjectField == 1 - object.ObjectField = None - self.assertTrue(object.ObjectField == None) + ob.ObjectField = None + assert ob.ObjectField is None - object.SpamField = None - self.assertTrue(object.SpamField == None) - # Primitive types and enums should not be set to null. +def test_enum_field(): + """Test enum fields.""" + from Python.Test import ShortEnum - def test(): - FieldTest().Int32Field = None + ob = FieldTest() + assert ob.EnumField == ShortEnum.Zero - self.assertRaises(TypeError, test) + ob.EnumField = ShortEnum.One + assert ob.EnumField == ShortEnum.One - def test(): - FieldTest().EnumField = None - self.assertRaises(TypeError, test) +def test_nullable_field(): + """Test nullable fields.""" + ob = FieldTest() + ob.StringField = None + assert ob.StringField is None -def test_suite(): - return unittest.makeSuite(FieldTests) + ob.ObjectField = None + assert ob.ObjectField is None + ob.SpamField = None + assert ob.SpamField is None -def main(): - unittest.TextTestRunner().run(test_suite()) + # Primitive types and enums should not be set to null. + with pytest.raises(TypeError): + FieldTest().Int32Field = None -if __name__ == '__main__': - main() + with pytest.raises(TypeError): + FieldTest().EnumField = None diff --git a/src/tests/test_generic.py b/src/tests/test_generic.py index 1e8b58f21..69cd4ee7f 100644 --- a/src/tests/test_generic.py +++ b/src/tests/test_generic.py @@ -1,803 +1,778 @@ -import clr - -clr.AddReference('Python.Test') - -from System.Collections.Generic import Dictionary, List -import sys, os, string, unittest, types -import Python.Test as Test -import System -import six - -if six.PY3: - long = int - unichr = chr - unicode = str - - -class GenericTests(unittest.TestCase): - """Test CLR generics support.""" - - def testPythonTypeAliasing(self): - """Test python type alias support with generics.""" - dict = Dictionary[str, str]() - self.assertEquals(dict.Count, 0) - dict.Add("one", "one") - self.assertTrue(dict["one"] == "one") - - dict = Dictionary[System.String, System.String]() - self.assertEquals(dict.Count, 0) - dict.Add("one", "one") - self.assertTrue(dict["one"] == "one") - - dict = Dictionary[int, int]() - self.assertEquals(dict.Count, 0) - dict.Add(1, 1) - self.assertTrue(dict[1] == 1) - - dict = Dictionary[System.Int32, System.Int32]() - self.assertEquals(dict.Count, 0) - dict.Add(1, 1) - self.assertTrue(dict[1] == 1) - - dict = Dictionary[long, long]() - self.assertEquals(dict.Count, 0) - dict.Add(long(1), long(1)) - self.assertTrue(dict[long(1)] == long(1)) - - dict = Dictionary[System.Int64, System.Int64]() - self.assertEquals(dict.Count, 0) - dict.Add(long(1), long(1)) - self.assertTrue(dict[long(1)] == long(1)) - - dict = Dictionary[float, float]() - self.assertEquals(dict.Count, 0) - dict.Add(1.5, 1.5) - self.assertTrue(dict[1.5] == 1.5) - - dict = Dictionary[System.Double, System.Double]() - self.assertEquals(dict.Count, 0) - dict.Add(1.5, 1.5) - self.assertTrue(dict[1.5] == 1.5) - - dict = Dictionary[bool, bool]() - self.assertEquals(dict.Count, 0) - dict.Add(True, False) - self.assertTrue(dict[True] == False) - - dict = Dictionary[System.Boolean, System.Boolean]() - self.assertEquals(dict.Count, 0) - dict.Add(True, False) - self.assertTrue(dict[True] == False) - - def testGenericReferenceType(self): - """Test usage of generic reference type definitions.""" - from Python.Test import GenericTypeDefinition - inst = GenericTypeDefinition[System.String, System.Int32]("one", 2) - self.assertTrue(inst.value1 == "one") - self.assertTrue(inst.value2 == 2) - - def testGenericValueType(self): - """Test usage of generic value type definitions.""" - inst = System.Nullable[System.Int32](10) - self.assertTrue(inst.HasValue) - self.assertTrue(inst.Value == 10) - - def testGenericInterface(self): - pass - - def testGenericDelegate(self): - pass - - def testOpenGenericType(self): - """ - Test behavior of reflected open constructed generic types. - """ - from Python.Test import DerivedFromOpenGeneric - - OpenGenericType = DerivedFromOpenGeneric.__bases__[0] - - def test(): - inst = OpenGenericType() - - self.assertRaises(TypeError, test) - - def test(): - type = OpenGenericType[System.String] - - self.assertRaises(TypeError, test) - - def testDerivedFromOpenGenericType(self): - """ - Test a generic type derived from an open generic type. - """ - from Python.Test import DerivedFromOpenGeneric - - type = DerivedFromOpenGeneric[System.String, System.String] - inst = type(1, 'two', 'three') - - self.assertTrue(inst.value1 == 1) - self.assertTrue(inst.value2 == 'two') - self.assertTrue(inst.value3 == 'three') - - def testGenericTypeNameResolution(self): - """ - Test the ability to disambiguate generic type names. - """ - from Python.Test import GenericNameTest1, GenericNameTest2 - - # If both a non-generic and generic type exist for a name, the - # unadorned name always resolves to the non-generic type. - _class = GenericNameTest1 - self.assertTrue(_class().value == 0) - self.assertTrue(_class.value == 0) - - # If no non-generic type exists for a name, the unadorned name - # cannot be instantiated. It can only be used to bind a generic. - - def test(): - inst = GenericNameTest2() - - self.assertRaises(TypeError, test) - - _class = GenericNameTest2[int] - self.assertTrue(_class().value == 1) - self.assertTrue(_class.value == 1) - - _class = GenericNameTest2[int, int] - self.assertTrue(_class().value == 2) - self.assertTrue(_class.value == 2) - - def _testGenericWrapperByType(self, ptype, value, test_type=0): - from Python.Test import GenericWrapper - import System - - inst = GenericWrapper[ptype](value) - self.assertTrue(inst.value == value) - - atype = System.Array[ptype] - items = atype([value, value, value]) - inst = GenericWrapper[atype](items) - self.assertTrue(len(inst.value) == 3) - self.assertTrue(inst.value[0] == value) - self.assertTrue(inst.value[1] == value) - - def testGenericTypeBinding(self): - """ - Test argument conversion / binding for generic methods. - """ - from Python.Test import InterfaceTest, ISayHello1, ShortEnum - import System - - self._testGenericWrapperByType(System.Boolean, True) - self._testGenericWrapperByType(bool, True) - self._testGenericWrapperByType(System.Byte, 255) - self._testGenericWrapperByType(System.SByte, 127) - self._testGenericWrapperByType(System.Char, six.u('A')) - self._testGenericWrapperByType(System.Int16, 32767) - self._testGenericWrapperByType(System.Int32, 2147483647) - self._testGenericWrapperByType(int, 2147483647) - self._testGenericWrapperByType(System.Int64, long(9223372036854775807)) - # Python 3 has no explicit long type, use System.Int64 instead - if not six.PY3: - self._testGenericWrapperByType(long, long(9223372036854775807)) - self._testGenericWrapperByType(System.UInt16, 65000) - self._testGenericWrapperByType(System.UInt32, long(4294967295)) - self._testGenericWrapperByType(System.UInt64, long(18446744073709551615)) - self._testGenericWrapperByType(System.Single, 3.402823e38) - self._testGenericWrapperByType(System.Double, 1.7976931348623157e308) - self._testGenericWrapperByType(float, 1.7976931348623157e308) - self._testGenericWrapperByType(System.Decimal, System.Decimal.One) - self._testGenericWrapperByType(System.String, "test") - self._testGenericWrapperByType(unicode, "test") - self._testGenericWrapperByType(str, "test") - self._testGenericWrapperByType(ShortEnum, ShortEnum.Zero) - self._testGenericWrapperByType(System.Object, InterfaceTest()) - self._testGenericWrapperByType(InterfaceTest, InterfaceTest()) - self._testGenericWrapperByType(ISayHello1, InterfaceTest()) - - def _testGenericMethodByType(self, ptype, value, test_type=0): - from Python.Test import GenericMethodTest, GenericStaticMethodTest - import System - - itype = GenericMethodTest[System.Type] - stype = GenericStaticMethodTest[System.Type] - - # Explicit selection (static method) - result = stype.Overloaded[ptype](value) - if test_type: - self.assertTrue(result.__class__ == value.__class__) - else: - self.assertTrue(result == value) - - # Type inference (static method) - result = stype.Overloaded(value) - self.assertTrue(result == value) - if test_type: - self.assertTrue(result.__class__ == value.__class__) - else: - self.assertTrue(result == value) - - # Explicit selection (instance method) - result = itype().Overloaded[ptype](value) - self.assertTrue(result == value) - if test_type: - self.assertTrue(result.__class__ == value.__class__) - else: - self.assertTrue(result == value) - - # Type inference (instance method) - result = itype().Overloaded(value) - self.assertTrue(result == value) - if test_type: - self.assertTrue(result.__class__ == value.__class__) - else: - self.assertTrue(result == value) - - atype = System.Array[ptype] - items = atype([value, value, value]) - - # Explicit selection (static method) - result = stype.Overloaded[atype](items) - if test_type: - self.assertTrue(len(result) == 3) - self.assertTrue(result[0].__class__ == value.__class__) - self.assertTrue(result[1].__class__ == value.__class__) - else: - self.assertTrue(len(result) == 3) - self.assertTrue(result[0] == value) - self.assertTrue(result[1] == value) - - # Type inference (static method) - result = stype.Overloaded(items) - if test_type: - self.assertTrue(len(result) == 3) - self.assertTrue(result[0].__class__ == value.__class__) - self.assertTrue(result[1].__class__ == value.__class__) - else: - self.assertTrue(len(result) == 3) - self.assertTrue(result[0] == value) - self.assertTrue(result[1] == value) - - # Explicit selection (instance method) - result = itype().Overloaded[atype](items) - if test_type: - self.assertTrue(len(result) == 3) - self.assertTrue(result[0].__class__ == value.__class__) - self.assertTrue(result[1].__class__ == value.__class__) - else: - self.assertTrue(len(result) == 3) - self.assertTrue(result[0] == value) - self.assertTrue(result[1] == value) - - # Type inference (instance method) - result = itype().Overloaded(items) - if test_type: - self.assertTrue(len(result) == 3) - self.assertTrue(result[0].__class__ == value.__class__) - self.assertTrue(result[1].__class__ == value.__class__) - else: - self.assertTrue(len(result) == 3) - self.assertTrue(result[0] == value) - self.assertTrue(result[1] == value) - - def testGenericMethodBinding(self): - from Python.Test import GenericMethodTest, GenericStaticMethodTest - from System import InvalidOperationException - - # Can invoke a static member on a closed generic type. - value = GenericStaticMethodTest[str].Overloaded() - self.assertTrue(value == 1) - - def test(): - # Cannot invoke a static member on an open type. - GenericStaticMethodTest.Overloaded() - - self.assertRaises(InvalidOperationException, test) - - # Can invoke an instance member on a closed generic type. - value = GenericMethodTest[str]().Overloaded() - self.assertTrue(value == 1) - - def test(): - # Cannot invoke an instance member on an open type, - # because the open type cannot be instantiated. - GenericMethodTest().Overloaded() - - self.assertRaises(TypeError, test) - - def testGenericMethodTypeHandling(self): - """ - Test argument conversion / binding for generic methods. - """ - from Python.Test import InterfaceTest, ISayHello1, ShortEnum - import System - - # XXX BUG: The value doesn't fit into Int64 and PythonNet doesn't - # recognize it as UInt64 for unknown reasons. - ## self._testGenericMethodByType(System.UInt64, 18446744073709551615L) - self._testGenericMethodByType(System.Boolean, True) - self._testGenericMethodByType(bool, True) - self._testGenericMethodByType(System.Byte, 255) - self._testGenericMethodByType(System.SByte, 127) - self._testGenericMethodByType(System.Char, six.u('A')) - self._testGenericMethodByType(System.Int16, 32767) - self._testGenericMethodByType(System.Int32, 2147483647) - self._testGenericMethodByType(int, 2147483647) - # Python 3 has no explicit long type, use System.Int64 instead - if not six.PY3: - self._testGenericMethodByType(System.Int64, long(9223372036854775807)) - self._testGenericMethodByType(long, long(9223372036854775807)) - self._testGenericMethodByType(System.UInt32, long(4294967295)) - self._testGenericMethodByType(System.Int64, long(1844674407370955161)) - self._testGenericMethodByType(System.UInt16, 65000) - self._testGenericMethodByType(System.Single, 3.402823e38) - self._testGenericMethodByType(System.Double, 1.7976931348623157e308) - self._testGenericMethodByType(float, 1.7976931348623157e308) - self._testGenericMethodByType(System.Decimal, System.Decimal.One) - self._testGenericMethodByType(System.String, "test") - self._testGenericMethodByType(unicode, "test") - self._testGenericMethodByType(str, "test") - self._testGenericMethodByType(ShortEnum, ShortEnum.Zero) - self._testGenericMethodByType(System.Object, InterfaceTest()) - self._testGenericMethodByType(InterfaceTest, InterfaceTest(), 1) - self._testGenericMethodByType(ISayHello1, InterfaceTest(), 1) - - def testCorrectOverloadSelection(self): - """ - Test correct overloading selection for common types. - """ - from System.Drawing import Font - - from System import (String, Double, Single, - Int16, Int32, Int64) - from System import Math - - substr = String("substring") - self.assertTrue(substr.Substring(2) == substr.Substring.__overloads__[Int32]( - Int32(2))) - self.assertTrue(substr.Substring(2, 3) == substr.Substring.__overloads__[Int32, Int32]( - Int32(2), Int32(3))) - - for atype, value1, value2 in zip([Double, Single, Int16, Int32, Int64], - [1.0, 1.0, 1, 1, 1], - [2.0, 0.5, 2, 0, -1]): - self.assertTrue(Math.Abs(atype(value1)) == Math.Abs.__overloads__[atype](atype(value1))) - self.assertTrue(Math.Abs(value1) == Math.Abs.__overloads__[atype](atype(value1))) - self.assertTrue( - Math.Max(atype(value1), - atype(value2)) == Math.Max.__overloads__[atype, atype]( - atype(value1), - atype(value2))) - if (atype is Int64) and six.PY2: - value2 = long(value2) - self.assertTrue( - Math.Max(atype(value1), - value2) == Math.Max.__overloads__[atype, atype]( - atype(value1), - atype(value2))) - - clr.AddReference("System.Runtime.InteropServices") - from System.Runtime.InteropServices import GCHandle, GCHandleType - from System import Array, Byte - CSArray = Array.CreateInstance(Byte, 1000) - handler = GCHandle.Alloc(CSArray, GCHandleType.Pinned) - - def testGenericMethodOverloadSelection(self): - """ - Test explicit overload selection with generic methods. - """ - from Python.Test import GenericMethodTest, GenericStaticMethodTest - type = GenericStaticMethodTest[str] - inst = GenericMethodTest[str]() - - # public static int Overloaded() - value = type.Overloaded() - self.assertTrue(value == 1) - - # public int Overloaded() - value = inst.Overloaded() - self.assertTrue(value == 1) - - # public static T Overloaded(T arg) (inferred) - value = type.Overloaded("test") - self.assertTrue(value == "test") - - # public T Overloaded(T arg) (inferred) - value = inst.Overloaded("test") - self.assertTrue(value == "test") - - # public static T Overloaded(T arg) (explicit) - value = type.Overloaded[str]("test") - self.assertTrue(value == "test") - - # public T Overloaded(T arg) (explicit) - value = inst.Overloaded[str]("test") - self.assertTrue(value == "test") - - # public static Q Overloaded(Q arg) - value = type.Overloaded[float](2.2) - self.assertTrue(value == 2.2) - - # public Q Overloaded(Q arg) - value = inst.Overloaded[float](2.2) - self.assertTrue(value == 2.2) - - # public static Q Overloaded(Q arg) - value = type.Overloaded[bool](True) - self.assertTrue(value == True) - - # public Q Overloaded(Q arg) - value = inst.Overloaded[bool](True) - self.assertTrue(value == True) - - # public static U Overloaded(Q arg1, U arg2) - value = type.Overloaded[bool, str](True, "true") - self.assertTrue(value == "true") - - # public U Overloaded(Q arg1, U arg2) - value = inst.Overloaded[bool, str](True, "true") - self.assertTrue(value == "true") - - # public static U Overloaded(Q arg1, U arg2) - value = type.Overloaded[str, bool]("true", True) - self.assertTrue(value == True) - - # public U Overloaded(Q arg1, U arg2) - value = inst.Overloaded[str, bool]("true", True) - self.assertTrue(value == True) - - # public static string Overloaded(int arg1, int arg2, string arg3) - value = type.Overloaded[str](123, 456, "success") - self.assertTrue(value == "success") - - # public string Overloaded(int arg1, int arg2, string arg3) - value = inst.Overloaded[str](123, 456, "success") - self.assertTrue(value == "success") - - def test(): - value = type.Overloaded[str, bool, int]("true", True, 1) - - self.assertRaises(TypeError, test) - - def test(): - value = inst.Overloaded[str, bool, int]("true", True, 1) - - self.assertRaises(TypeError, test) - - def testMethodOverloadSelectionWithGenericTypes(self): - """Check method overload selection using generic types.""" - from Python.Test import ISayHello1, InterfaceTest, ShortEnum - from Python.Test import MethodTest, GenericWrapper - inst = InterfaceTest() - - vtype = GenericWrapper[System.Boolean] - input = vtype(True) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == True) - - vtype = GenericWrapper[bool] - input = vtype(True) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == True) - - vtype = GenericWrapper[System.Byte] - input = vtype(255) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == 255) - - vtype = GenericWrapper[System.SByte] - input = vtype(127) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == 127) - - vtype = GenericWrapper[System.Char] - input = vtype(six.u('A')) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == six.u('A')) - - vtype = GenericWrapper[System.Char] - input = vtype(65535) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == unichr(65535)) - - vtype = GenericWrapper[System.Int16] - input = vtype(32767) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == 32767) - - vtype = GenericWrapper[System.Int32] - input = vtype(2147483647) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == 2147483647) - - vtype = GenericWrapper[int] - input = vtype(2147483647) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == 2147483647) - - vtype = GenericWrapper[System.Int64] - input = vtype(long(9223372036854775807)) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == long(9223372036854775807)) - - # Python 3 has no explicit long type, use System.Int64 instead - if not six.PY3: - vtype = GenericWrapper[long] - input = vtype(long(9223372036854775807)) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == long(9223372036854775807)) - - vtype = GenericWrapper[System.UInt16] - input = vtype(65000) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == 65000) - - vtype = GenericWrapper[System.UInt32] - input = vtype(long(4294967295)) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == long(4294967295)) - - vtype = GenericWrapper[System.UInt64] - input = vtype(long(18446744073709551615)) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == long(18446744073709551615)) - - vtype = GenericWrapper[System.Single] - input = vtype(3.402823e38) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == 3.402823e38) - - vtype = GenericWrapper[System.Double] - input = vtype(1.7976931348623157e308) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == 1.7976931348623157e308) - - vtype = GenericWrapper[float] - input = vtype(1.7976931348623157e308) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == 1.7976931348623157e308) - - vtype = GenericWrapper[System.Decimal] - input = vtype(System.Decimal.One) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == System.Decimal.One) - - vtype = GenericWrapper[System.String] - input = vtype("spam") - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == "spam") - - vtype = GenericWrapper[str] - input = vtype("spam") - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == "spam") - - vtype = GenericWrapper[ShortEnum] - input = vtype(ShortEnum.Zero) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value == ShortEnum.Zero) - - vtype = GenericWrapper[System.Object] - input = vtype(inst) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value.__class__ == inst.__class__) - - vtype = GenericWrapper[InterfaceTest] - input = vtype(inst) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value.__class__ == inst.__class__) - - vtype = GenericWrapper[ISayHello1] - input = vtype(inst) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value.value.__class__ == inst.__class__) - - vtype = System.Array[GenericWrapper[int]] - input = vtype([GenericWrapper[int](0), GenericWrapper[int](1)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == 0) - self.assertTrue(value[1].value == 1) - - def testOverloadSelectionWithArraysOfGenericTypes(self): - """Check overload selection using arrays of generic types.""" - from Python.Test import ISayHello1, InterfaceTest, ShortEnum - from Python.Test import MethodTest, GenericWrapper - inst = InterfaceTest() - - gtype = GenericWrapper[System.Boolean] - vtype = System.Array[gtype] - input = vtype([gtype(True), gtype(True)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == True) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[bool] - vtype = System.Array[gtype] - input = vtype([gtype(True), gtype(True)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == True) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[System.Byte] - vtype = System.Array[gtype] - input = vtype([gtype(255), gtype(255)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == 255) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[System.SByte] - vtype = System.Array[gtype] - input = vtype([gtype(127), gtype(127)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == 127) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[System.Char] - vtype = System.Array[gtype] - input = vtype([gtype(six.u('A')), gtype(six.u('A'))]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == six.u('A')) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[System.Char] - vtype = System.Array[gtype] - input = vtype([gtype(65535), gtype(65535)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == unichr(65535)) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[System.Int16] - vtype = System.Array[gtype] - input = vtype([gtype(32767), gtype(32767)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == 32767) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[System.Int32] - vtype = System.Array[gtype] - input = vtype([gtype(2147483647), gtype(2147483647)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == 2147483647) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[int] - vtype = System.Array[gtype] - input = vtype([gtype(2147483647), gtype(2147483647)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == 2147483647) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[System.Int64] - vtype = System.Array[gtype] - input = vtype([gtype(long(9223372036854775807)), - gtype(long(9223372036854775807))]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == long(9223372036854775807)) - self.assertTrue(value.Length == 2) - - # Python 3 has no explicit long type, use System.Int64 instead - if not six.PY3: - gtype = GenericWrapper[long] - vtype = System.Array[gtype] - input = vtype([gtype(long(9223372036854775807)), - gtype(long(9223372036854775807))]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == long(9223372036854775807)) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[System.UInt16] - vtype = System.Array[gtype] - input = vtype([gtype(65000), gtype(65000)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == 65000) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[System.UInt32] - vtype = System.Array[gtype] - input = vtype([gtype(long(4294967295)), gtype(long(4294967295))]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == long(4294967295)) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[System.UInt64] - vtype = System.Array[gtype] - input = vtype([gtype(long(18446744073709551615)), - gtype(long(18446744073709551615))]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == long(18446744073709551615)) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[System.Single] - vtype = System.Array[gtype] - input = vtype([gtype(3.402823e38), gtype(3.402823e38)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == 3.402823e38) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[System.Double] - vtype = System.Array[gtype] - input = vtype([gtype(1.7976931348623157e308), - gtype(1.7976931348623157e308)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == 1.7976931348623157e308) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[float] - vtype = System.Array[gtype] - input = vtype([gtype(1.7976931348623157e308), - gtype(1.7976931348623157e308)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == 1.7976931348623157e308) - self.assertTrue(value.Length == 2) +# -*- coding: utf-8 -*- - gtype = GenericWrapper[System.Decimal] - vtype = System.Array[gtype] - input = vtype([gtype(System.Decimal.One), - gtype(System.Decimal.One)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == System.Decimal.One) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[System.String] - vtype = System.Array[gtype] - input = vtype([gtype("spam"), gtype("spam")]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == "spam") - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[str] - vtype = System.Array[gtype] - input = vtype([gtype("spam"), gtype("spam")]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == "spam") - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[ShortEnum] - vtype = System.Array[gtype] - input = vtype([gtype(ShortEnum.Zero), gtype(ShortEnum.Zero)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value == ShortEnum.Zero) - self.assertTrue(value.Length == 2) +"""Test CLR generics support.""" - gtype = GenericWrapper[System.Object] - vtype = System.Array[gtype] - input = vtype([gtype(inst), gtype(inst)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value.__class__ == inst.__class__) - self.assertTrue(value.Length == 2) - - gtype = GenericWrapper[InterfaceTest] - vtype = System.Array[gtype] - input = vtype([gtype(inst), gtype(inst)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value.__class__ == inst.__class__) - self.assertTrue(value.Length == 2) +import clr - gtype = GenericWrapper[ISayHello1] +import System +import pytest + +from ._compat import PY2, long, unicode, unichr, zip + + +def assert_generic_wrapper_by_type(ptype, value): + """Test Helper""" + from Python.Test import GenericWrapper + import System + + inst = GenericWrapper[ptype](value) + assert inst.value == value + + atype = System.Array[ptype] + items = atype([value, value, value]) + inst = GenericWrapper[atype](items) + assert len(inst.value) == 3 + assert inst.value[0] == value + assert inst.value[1] == value + + +def assert_generic_method_by_type(ptype, value, test_type=0): + """Test Helper""" + from Python.Test import GenericMethodTest, GenericStaticMethodTest + import System + + itype = GenericMethodTest[System.Type] + stype = GenericStaticMethodTest[System.Type] + + # Explicit selection (static method) + result = stype.Overloaded[ptype](value) + if test_type: + assert result.__class__ == value.__class__ + else: + assert result == value + + # Type inference (static method) + result = stype.Overloaded(value) + assert result == value + if test_type: + assert result.__class__ == value.__class__ + else: + assert result == value + + # Explicit selection (instance method) + result = itype().Overloaded[ptype](value) + assert result == value + if test_type: + assert result.__class__ == value.__class__ + else: + assert result == value + + # Type inference (instance method) + result = itype().Overloaded(value) + assert result == value + if test_type: + assert result.__class__ == value.__class__ + else: + assert result == value + + atype = System.Array[ptype] + items = atype([value, value, value]) + + # Explicit selection (static method) + result = stype.Overloaded[atype](items) + if test_type: + assert len(result) == 3 + assert result[0].__class__ == value.__class__ + assert result[1].__class__ == value.__class__ + else: + assert len(result) == 3 + assert result[0] == value + assert result[1] == value + + # Type inference (static method) + result = stype.Overloaded(items) + if test_type: + assert len(result) == 3 + assert result[0].__class__ == value.__class__ + assert result[1].__class__ == value.__class__ + else: + assert len(result) == 3 + assert result[0] == value + assert result[1] == value + + # Explicit selection (instance method) + result = itype().Overloaded[atype](items) + if test_type: + assert len(result) == 3 + assert result[0].__class__ == value.__class__ + assert result[1].__class__ == value.__class__ + else: + assert len(result) == 3 + assert result[0] == value + assert result[1] == value + + # Type inference (instance method) + result = itype().Overloaded(items) + if test_type: + assert len(result) == 3 + assert result[0].__class__ == value.__class__ + assert result[1].__class__ == value.__class__ + else: + assert len(result) == 3 + assert result[0] == value + assert result[1] == value + + +def test_python_type_aliasing(): + """Test python type alias support with generics.""" + from System.Collections.Generic import Dictionary + + dict_ = Dictionary[str, str]() + assert dict_.Count == 0 + dict_.Add("one", "one") + assert dict_["one"] == "one" + + dict_ = Dictionary[System.String, System.String]() + assert dict_.Count == 0 + dict_.Add("one", "one") + assert dict_["one"] == "one" + + dict_ = Dictionary[int, int]() + assert dict_.Count == 0 + dict_.Add(1, 1) + assert dict_[1] == 1 + + dict_ = Dictionary[System.Int32, System.Int32]() + assert dict_.Count == 0 + dict_.Add(1, 1) + assert dict_[1] == 1 + + dict_ = Dictionary[long, long]() + assert dict_.Count == 0 + dict_.Add(long(1), long(1)) + assert dict_[long(1)] == long(1) + + dict_ = Dictionary[System.Int64, System.Int64]() + assert dict_.Count == 0 + dict_.Add(long(1), long(1)) + assert dict_[long(1)] == long(1) + + dict_ = Dictionary[float, float]() + assert dict_.Count == 0 + dict_.Add(1.5, 1.5) + assert dict_[1.5] == 1.5 + + dict_ = Dictionary[System.Double, System.Double]() + assert dict_.Count == 0 + dict_.Add(1.5, 1.5) + assert dict_[1.5] == 1.5 + + dict_ = Dictionary[bool, bool]() + assert dict_.Count == 0 + dict_.Add(True, False) + assert dict_[True] is False + + dict_ = Dictionary[System.Boolean, System.Boolean]() + assert dict_.Count == 0 + dict_.Add(True, False) + assert dict_[True] is False + + +def test_generic_reference_type(): + """Test usage of generic reference type definitions.""" + from Python.Test import GenericTypeDefinition + + inst = GenericTypeDefinition[System.String, System.Int32]("one", 2) + assert inst.value1 == "one" + assert inst.value2 == 2 + + +def test_generic_value_type(): + """Test usage of generic value type definitions.""" + inst = System.Nullable[System.Int32](10) + assert inst.HasValue + assert inst.Value == 10 + + +def test_generic_interface(): + # TODO NotImplemented + pass + + +def test_generic_delegate(): + # TODO NotImplemented + pass + + +def test_open_generic_type(): + """Test behavior of reflected open constructed generic types.""" + from Python.Test import DerivedFromOpenGeneric + + open_generic_type = DerivedFromOpenGeneric.__bases__[0] + + with pytest.raises(TypeError): + _ = open_generic_type() + + with pytest.raises(TypeError): + _ = open_generic_type[System.String] + + +def test_derived_from_open_generic_type(): + """Test a generic type derived from an open generic type.""" + from Python.Test import DerivedFromOpenGeneric + + type_ = DerivedFromOpenGeneric[System.String, System.String] + inst = type_(1, 'two', 'three') + + assert inst.value1 == 1 + assert inst.value2 == 'two' + assert inst.value3 == 'three' + + +def test_generic_type_name_resolution(): + """Test the ability to disambiguate generic type names.""" + from Python.Test import GenericNameTest1, GenericNameTest2 + + # If both a non-generic and generic type exist for a name, the + # unadorned name always resolves to the non-generic type. + _class = GenericNameTest1 + assert _class().value == 0 + assert _class.value == 0 + + # If no non-generic type exists for a name, the unadorned name + # cannot be instantiated. It can only be used to bind a generic. + + with pytest.raises(TypeError): + _ = GenericNameTest2() + + _class = GenericNameTest2[int] + assert _class().value == 1 + assert _class.value == 1 + + _class = GenericNameTest2[int, int] + assert _class().value == 2 + assert _class.value == 2 + + +def test_generic_type_binding(): + """Test argument conversion / binding for generic methods.""" + from Python.Test import InterfaceTest, ISayHello1, ShortEnum + import System + + assert_generic_wrapper_by_type(System.Boolean, True) + assert_generic_wrapper_by_type(bool, True) + assert_generic_wrapper_by_type(System.Byte, 255) + assert_generic_wrapper_by_type(System.SByte, 127) + assert_generic_wrapper_by_type(System.Char, u'A') + assert_generic_wrapper_by_type(System.Int16, 32767) + assert_generic_wrapper_by_type(System.Int32, 2147483647) + assert_generic_wrapper_by_type(int, 2147483647) + assert_generic_wrapper_by_type(System.Int64, long(9223372036854775807)) + # Python 3 has no explicit long type, use System.Int64 instead + if PY2: + assert_generic_wrapper_by_type(long, long(9223372036854775807)) + assert_generic_wrapper_by_type(System.UInt16, 65000) + assert_generic_wrapper_by_type(System.UInt32, long(4294967295)) + assert_generic_wrapper_by_type(System.UInt64, long(18446744073709551615)) + assert_generic_wrapper_by_type(System.Single, 3.402823e38) + assert_generic_wrapper_by_type(System.Double, 1.7976931348623157e308) + assert_generic_wrapper_by_type(float, 1.7976931348623157e308) + assert_generic_wrapper_by_type(System.Decimal, System.Decimal.One) + assert_generic_wrapper_by_type(System.String, "test") + assert_generic_wrapper_by_type(unicode, "test") + assert_generic_wrapper_by_type(str, "test") + assert_generic_wrapper_by_type(ShortEnum, ShortEnum.Zero) + assert_generic_wrapper_by_type(System.Object, InterfaceTest()) + assert_generic_wrapper_by_type(InterfaceTest, InterfaceTest()) + assert_generic_wrapper_by_type(ISayHello1, InterfaceTest()) + + +def test_generic_method_binding(): + from Python.Test import GenericMethodTest, GenericStaticMethodTest + from System import InvalidOperationException + + # Can invoke a static member on a closed generic type. + value = GenericStaticMethodTest[str].Overloaded() + assert value == 1 + + with pytest.raises(InvalidOperationException): + # Cannot invoke a static member on an open type. + GenericStaticMethodTest.Overloaded() + + # Can invoke an instance member on a closed generic type. + value = GenericMethodTest[str]().Overloaded() + assert value == 1 + + with pytest.raises(TypeError): + # Cannot invoke an instance member on an open type, + # because the open type cannot be instantiated. + GenericMethodTest().Overloaded() + + +def test_generic_method_type_handling(): + """Test argument conversion / binding for generic methods.""" + from Python.Test import InterfaceTest, ISayHello1, ShortEnum + import System + + # FIXME: The value doesn't fit into Int64 and PythonNet doesn't + # recognize it as UInt64 for unknown reasons. + # assert_generic_method_by_type(System.UInt64, 18446744073709551615L) + assert_generic_method_by_type(System.Boolean, True) + assert_generic_method_by_type(bool, True) + assert_generic_method_by_type(System.Byte, 255) + assert_generic_method_by_type(System.SByte, 127) + assert_generic_method_by_type(System.Char, u'A') + assert_generic_method_by_type(System.Int16, 32767) + assert_generic_method_by_type(System.Int32, 2147483647) + assert_generic_method_by_type(int, 2147483647) + # Python 3 has no explicit long type, use System.Int64 instead + if PY2: + assert_generic_method_by_type(System.Int64, long(9223372036854775807)) + assert_generic_method_by_type(long, long(9223372036854775807)) + assert_generic_method_by_type(System.UInt32, long(4294967295)) + assert_generic_method_by_type(System.Int64, long(1844674407370955161)) + assert_generic_method_by_type(System.UInt16, 65000) + assert_generic_method_by_type(System.Single, 3.402823e38) + assert_generic_method_by_type(System.Double, 1.7976931348623157e308) + assert_generic_method_by_type(float, 1.7976931348623157e308) + assert_generic_method_by_type(System.Decimal, System.Decimal.One) + assert_generic_method_by_type(System.String, "test") + assert_generic_method_by_type(unicode, "test") + assert_generic_method_by_type(str, "test") + assert_generic_method_by_type(ShortEnum, ShortEnum.Zero) + assert_generic_method_by_type(System.Object, InterfaceTest()) + assert_generic_method_by_type(InterfaceTest, InterfaceTest(), 1) + assert_generic_method_by_type(ISayHello1, InterfaceTest(), 1) + + +def test_correct_overload_selection(): + """Test correct overloading selection for common types.""" + from System import (String, Double, Single, + Int16, Int32, Int64) + from System import Math + + substr = String("substring") + assert substr.Substring(2) == substr.Substring.__overloads__[Int32]( + Int32(2)) + assert substr.Substring(2, 3) == substr.Substring.__overloads__[Int32, Int32]( + Int32(2), Int32(3)) + + for atype, value1, value2 in zip([Double, Single, Int16, Int32, Int64], + [1.0, 1.0, 1, 1, 1], + [2.0, 0.5, 2, 0, -1]): + assert Math.Abs(atype(value1)) == Math.Abs.__overloads__[atype](atype(value1)) + assert Math.Abs(value1) == Math.Abs.__overloads__[atype](atype(value1)) + assert Math.Max(atype(value1), + atype(value2)) == Math.Max.__overloads__[atype, atype]( + atype(value1), atype(value2)) + if PY2 and atype is Int64: + value2 = long(value2) + assert Math.Max(atype(value1), + value2) == Math.Max.__overloads__[atype, atype]( + atype(value1), atype(value2)) + + clr.AddReference("System.Runtime.InteropServices") + from System.Runtime.InteropServices import GCHandle, GCHandleType + from System import Array, Byte + cs_array = Array.CreateInstance(Byte, 1000) + handler = GCHandle.Alloc(cs_array, GCHandleType.Pinned) + + +def test_generic_method_overload_selection(): + """Test explicit overload selection with generic methods.""" + from Python.Test import GenericMethodTest, GenericStaticMethodTest + + type = GenericStaticMethodTest[str] + inst = GenericMethodTest[str]() + + # public static int Overloaded() + value = type.Overloaded() + assert value == 1 + + # public int Overloaded() + value = inst.Overloaded() + assert value == 1 + + # public static T Overloaded(T arg) (inferred) + value = type.Overloaded("test") + assert value == "test" + + # public T Overloaded(T arg) (inferred) + value = inst.Overloaded("test") + assert value == "test" + + # public static T Overloaded(T arg) (explicit) + value = type.Overloaded[str]("test") + assert value == "test" + + # public T Overloaded(T arg) (explicit) + value = inst.Overloaded[str]("test") + assert value == "test" + + # public static Q Overloaded(Q arg) + value = type.Overloaded[float](2.2) + assert value == 2.2 + + # public Q Overloaded(Q arg) + value = inst.Overloaded[float](2.2) + assert value == 2.2 + + # public static Q Overloaded(Q arg) + value = type.Overloaded[bool](True) + assert value is True + + # public Q Overloaded(Q arg) + value = inst.Overloaded[bool](True) + assert value is True + + # public static U Overloaded(Q arg1, U arg2) + value = type.Overloaded[bool, str](True, "true") + assert value == "true" + + # public U Overloaded(Q arg1, U arg2) + value = inst.Overloaded[bool, str](True, "true") + assert value == "true" + + # public static U Overloaded(Q arg1, U arg2) + value = type.Overloaded[str, bool]("true", True) + assert value is True + + # public U Overloaded(Q arg1, U arg2) + value = inst.Overloaded[str, bool]("true", True) + assert value is True + + # public static string Overloaded(int arg1, int arg2, string arg3) + value = type.Overloaded[str](123, 456, "success") + assert value == "success" + + # public string Overloaded(int arg1, int arg2, string arg3) + value = inst.Overloaded[str](123, 456, "success") + assert value == "success" + + with pytest.raises(TypeError): + _ = type.Overloaded[str, bool, int]("true", True, 1) + + with pytest.raises(TypeError): + _ = inst.Overloaded[str, bool, int]("true", True, 1) + + +def test_method_overload_selection_with_generic_types(): + """Check method overload selection using generic types.""" + from Python.Test import ISayHello1, InterfaceTest, ShortEnum + from Python.Test import MethodTest, GenericWrapper + + inst = InterfaceTest() + + vtype = GenericWrapper[System.Boolean] + input_ = vtype(True) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value is True + + vtype = GenericWrapper[bool] + input_ = vtype(True) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value is True + + vtype = GenericWrapper[System.Byte] + input_ = vtype(255) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == 255 + + vtype = GenericWrapper[System.SByte] + input_ = vtype(127) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == 127 + + vtype = GenericWrapper[System.Char] + input_ = vtype(u'A') + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == u'A' + + vtype = GenericWrapper[System.Char] + input_ = vtype(65535) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == unichr(65535) + + vtype = GenericWrapper[System.Int16] + input_ = vtype(32767) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == 32767 + + vtype = GenericWrapper[System.Int32] + input_ = vtype(2147483647) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == 2147483647 + + vtype = GenericWrapper[int] + input_ = vtype(2147483647) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == 2147483647 + + vtype = GenericWrapper[System.Int64] + input_ = vtype(long(9223372036854775807)) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == long(9223372036854775807) + + # Python 3 has no explicit long type, use System.Int64 instead + if PY2: + vtype = GenericWrapper[long] + input_ = vtype(long(9223372036854775807)) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == long(9223372036854775807) + + vtype = GenericWrapper[System.UInt16] + input_ = vtype(65000) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == 65000 + + vtype = GenericWrapper[System.UInt32] + input_ = vtype(long(4294967295)) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == long(4294967295) + + vtype = GenericWrapper[System.UInt64] + input_ = vtype(long(18446744073709551615)) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == long(18446744073709551615) + + vtype = GenericWrapper[System.Single] + input_ = vtype(3.402823e38) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == 3.402823e38 + + vtype = GenericWrapper[System.Double] + input_ = vtype(1.7976931348623157e308) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == 1.7976931348623157e308 + + vtype = GenericWrapper[float] + input_ = vtype(1.7976931348623157e308) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == 1.7976931348623157e308 + + vtype = GenericWrapper[System.Decimal] + input_ = vtype(System.Decimal.One) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == System.Decimal.One + + vtype = GenericWrapper[System.String] + input_ = vtype("spam") + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == "spam" + + vtype = GenericWrapper[str] + input_ = vtype("spam") + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == "spam" + + vtype = GenericWrapper[ShortEnum] + input_ = vtype(ShortEnum.Zero) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value == ShortEnum.Zero + + vtype = GenericWrapper[System.Object] + input_ = vtype(inst) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value.__class__ == inst.__class__ + + vtype = GenericWrapper[InterfaceTest] + input_ = vtype(inst) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value.__class__ == inst.__class__ + + vtype = GenericWrapper[ISayHello1] + input_ = vtype(inst) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value.value.__class__ == inst.__class__ + + vtype = System.Array[GenericWrapper[int]] + input_ = vtype([GenericWrapper[int](0), GenericWrapper[int](1)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == 0 + assert value[1].value == 1 + + +def test_overload_selection_with_arrays_of_generic_types(): + """Check overload selection using arrays of generic types.""" + from Python.Test import ISayHello1, InterfaceTest, ShortEnum + from Python.Test import MethodTest, GenericWrapper + + inst = InterfaceTest() + + gtype = GenericWrapper[System.Boolean] + vtype = System.Array[gtype] + input_ = vtype([gtype(True), gtype(True)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value is True + assert value.Length == 2 + + gtype = GenericWrapper[bool] + vtype = System.Array[gtype] + input_ = vtype([gtype(True), gtype(True)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value is True + assert value.Length == 2 + + gtype = GenericWrapper[System.Byte] + vtype = System.Array[gtype] + input_ = vtype([gtype(255), gtype(255)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == 255 + assert value.Length == 2 + + gtype = GenericWrapper[System.SByte] + vtype = System.Array[gtype] + input_ = vtype([gtype(127), gtype(127)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == 127 + assert value.Length == 2 + + gtype = GenericWrapper[System.Char] + vtype = System.Array[gtype] + input_ = vtype([gtype(u'A'), gtype(u'A')]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == u'A' + assert value.Length == 2 + + gtype = GenericWrapper[System.Char] + vtype = System.Array[gtype] + input_ = vtype([gtype(65535), gtype(65535)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == unichr(65535) + assert value.Length == 2 + + gtype = GenericWrapper[System.Int16] + vtype = System.Array[gtype] + input_ = vtype([gtype(32767), gtype(32767)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == 32767 + assert value.Length == 2 + + gtype = GenericWrapper[System.Int32] + vtype = System.Array[gtype] + input_ = vtype([gtype(2147483647), gtype(2147483647)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == 2147483647 + assert value.Length == 2 + + gtype = GenericWrapper[int] + vtype = System.Array[gtype] + input_ = vtype([gtype(2147483647), gtype(2147483647)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == 2147483647 + assert value.Length == 2 + + gtype = GenericWrapper[System.Int64] + vtype = System.Array[gtype] + input_ = vtype([gtype(long(9223372036854775807)), + gtype(long(9223372036854775807))]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == long(9223372036854775807) + assert value.Length == 2 + + # Python 3 has no explicit long type, use System.Int64 instead + if PY2: + gtype = GenericWrapper[long] vtype = System.Array[gtype] - input = vtype([gtype(inst), gtype(inst)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].value.__class__ == inst.__class__) - self.assertTrue(value.Length == 2) - - def testGenericOverloadSelectionMagicNameOnly(self): - """Test using only __overloads__ to select on type & sig""" - # XXX NotImplemented - pass - - def testNestedGenericClass(self): - """Check nested generic classes.""" - # XXX NotImplemented - pass - - -def test_suite(): - return unittest.makeSuite(GenericTests) - - -def main(): - unittest.TextTestRunner().run(test_suite()) - - -if __name__ == '__main__': - main() + input_ = vtype([gtype(long(9223372036854775807)), + gtype(long(9223372036854775807))]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == long(9223372036854775807) + assert value.Length == 2 + + gtype = GenericWrapper[System.UInt16] + vtype = System.Array[gtype] + input_ = vtype([gtype(65000), gtype(65000)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == 65000 + assert value.Length == 2 + + gtype = GenericWrapper[System.UInt32] + vtype = System.Array[gtype] + input_ = vtype([gtype(long(4294967295)), gtype(long(4294967295))]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == long(4294967295) + assert value.Length == 2 + + gtype = GenericWrapper[System.UInt64] + vtype = System.Array[gtype] + input_ = vtype([gtype(long(18446744073709551615)), + gtype(long(18446744073709551615))]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == long(18446744073709551615) + assert value.Length == 2 + + gtype = GenericWrapper[System.Single] + vtype = System.Array[gtype] + input_ = vtype([gtype(3.402823e38), gtype(3.402823e38)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == 3.402823e38 + assert value.Length == 2 + + gtype = GenericWrapper[System.Double] + vtype = System.Array[gtype] + input_ = vtype([gtype(1.7976931348623157e308), + gtype(1.7976931348623157e308)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == 1.7976931348623157e308 + assert value.Length == 2 + + gtype = GenericWrapper[float] + vtype = System.Array[gtype] + input_ = vtype([gtype(1.7976931348623157e308), + gtype(1.7976931348623157e308)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == 1.7976931348623157e308 + assert value.Length == 2 + + gtype = GenericWrapper[System.Decimal] + vtype = System.Array[gtype] + input_ = vtype([gtype(System.Decimal.One), + gtype(System.Decimal.One)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == System.Decimal.One + assert value.Length == 2 + + gtype = GenericWrapper[System.String] + vtype = System.Array[gtype] + input_ = vtype([gtype("spam"), gtype("spam")]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == "spam" + assert value.Length == 2 + + gtype = GenericWrapper[str] + vtype = System.Array[gtype] + input_ = vtype([gtype("spam"), gtype("spam")]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == "spam" + assert value.Length == 2 + + gtype = GenericWrapper[ShortEnum] + vtype = System.Array[gtype] + input_ = vtype([gtype(ShortEnum.Zero), gtype(ShortEnum.Zero)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value == ShortEnum.Zero + assert value.Length == 2 + + gtype = GenericWrapper[System.Object] + vtype = System.Array[gtype] + input_ = vtype([gtype(inst), gtype(inst)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value.__class__ == inst.__class__ + assert value.Length == 2 + + gtype = GenericWrapper[InterfaceTest] + vtype = System.Array[gtype] + input_ = vtype([gtype(inst), gtype(inst)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value.__class__ == inst.__class__ + assert value.Length == 2 + + gtype = GenericWrapper[ISayHello1] + vtype = System.Array[gtype] + input_ = vtype([gtype(inst), gtype(inst)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].value.__class__ == inst.__class__ + assert value.Length == 2 + + +def test_generic_overload_selection_magic_name_only(): + """Test using only __overloads__ to select on type & sig""" + # TODO NotImplemented + pass + + +def test_nested_generic_class(): + """Check nested generic classes.""" + # TODO NotImplemented + pass diff --git a/src/tests/test_import.py b/src/tests/test_import.py new file mode 100644 index 000000000..42cafc4df --- /dev/null +++ b/src/tests/test_import.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- + +"""Test the import statement.""" + +import pytest + + +def test_relative_missing_import(): + """Test that a relative missing import doesn't crash. + Some modules use this to check if a package is installed. + Relative import in the site-packages folder""" + with pytest.raises(ImportError): + from . import _missing_import diff --git a/src/tests/test_indexer.py b/src/tests/test_indexer.py index 5e74c76f0..6f18550d9 100644 --- a/src/tests/test_indexer.py +++ b/src/tests/test_indexer.py @@ -1,687 +1,599 @@ -import sys, os, string, unittest, types -import clr +# -*- coding: utf-8 -*- -clr.AddReference("Python.Test") -import Python.Test as Test -import six - -if six.PY3: - long = int - unichr = chr - - -class IndexerTests(unittest.TestCase): - """Test support for indexer properties.""" - - def testPublicIndexer(self): - """Test public indexers.""" - object = Test.PublicIndexerTest() - - object[0] = "zero" - self.assertTrue(object[0] == "zero") - - object[1] = "one" - self.assertTrue(object[1] == "one") - - self.assertTrue(object[10] == None) - - def testProtectedIndexer(self): - """Test protected indexers.""" - object = Test.ProtectedIndexerTest() - - object[0] = "zero" - self.assertTrue(object[0] == "zero") - - object[1] = "one" - self.assertTrue(object[1] == "one") - - self.assertTrue(object[10] == None) - - def testInternalIndexer(self): - """Test internal indexers.""" - object = Test.InternalIndexerTest() - - def test(): - object[0] = "zero" - - self.assertRaises(TypeError, test) +"""Test support for indexer properties.""" - def test(): - Test.InternalIndexerTest.__getitem__(object, 0) - - self.assertRaises(TypeError, test) - - def test(): - object.__getitem__(0) - - self.assertRaises(TypeError, test) - - def testPrivateIndexer(self): - """Test private indexers.""" - object = Test.PrivateIndexerTest() - - def test(): - object[0] = "zero" - - self.assertRaises(TypeError, test) - - def test(): - Test.PrivateIndexerTest.__getitem__(object, 0) - - self.assertRaises(TypeError, test) - - def test(): - object.__getitem__(0) - - self.assertRaises(TypeError, test) - - def testBooleanIndexer(self): - """Test boolean indexers.""" - object = Test.BooleanIndexerTest() - - self.assertTrue(object[True] == None) - self.assertTrue(object[1] == None) - - object[0] = "false" - self.assertTrue(object[0] == "false") - - object[1] = "true" - self.assertTrue(object[1] == "true") +import Python.Test as Test +import pytest - object[False] = "false" - self.assertTrue(object[False] == "false") +from ._compat import long, unichr - object[True] = "true" - self.assertTrue(object[True] == "true") - def testByteIndexer(self): - """Test byte indexers.""" - object = Test.ByteIndexerTest() - max = 255 - min = 0 +def test_public_indexer(): + """Test public indexers.""" + ob = Test.PublicIndexerTest() - self.assertTrue(object[max] == None) + ob[0] = "zero" + assert ob[0] == "zero" - object[max] = str(max) - self.assertTrue(object[max] == str(max)) + ob[1] = "one" + assert ob[1] == "one" - object[min] = str(min) - self.assertTrue(object[min] == str(min)) + assert ob[10] is None - def test(): - object = Test.ByteIndexerTest() - object["wrong"] - self.assertRaises(TypeError, test) +def test_protected_indexer(): + """Test protected indexers.""" + ob = Test.ProtectedIndexerTest() - def test(): - object = Test.ByteIndexerTest() - object["wrong"] = "wrong" + ob[0] = "zero" + assert ob[0] == "zero" - self.assertRaises(TypeError, test) + ob[1] = "one" + assert ob[1] == "one" - def testSByteIndexer(self): - """Test sbyte indexers.""" - object = Test.SByteIndexerTest() - max = 127 - min = -128 + assert ob[10] is None - self.assertTrue(object[max] == None) - object[max] = str(max) - self.assertTrue(object[max] == str(max)) +def test_internal_indexer(): + """Test internal indexers.""" + ob = Test.InternalIndexerTest() - object[min] = str(min) - self.assertTrue(object[min] == str(min)) + with pytest.raises(TypeError): + ob[0] = "zero" - def test(): - object = Test.SByteIndexerTest() - object["wrong"] + with pytest.raises(TypeError): + Test.InternalIndexerTest.__getitem__(ob, 0) - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob.__getitem__(0) - def test(): - object = Test.SByteIndexerTest() - object["wrong"] = "wrong" - self.assertRaises(TypeError, test) +def test_private_indexer(): + """Test private indexers.""" + ob = Test.PrivateIndexerTest() - def testCharIndexer(self): - """Test char indexers.""" - object = Test.CharIndexerTest() - max = unichr(65535) - min = unichr(0) + with pytest.raises(TypeError): + ob[0] = "zero" - self.assertTrue(object[max] == None) + with pytest.raises(TypeError): + Test.PrivateIndexerTest.__getitem__(ob, 0) - object[max] = "max" - self.assertTrue(object[max] == "max") + with pytest.raises(TypeError): + ob.__getitem__(0) - object[min] = "min" - self.assertTrue(object[min] == "min") - def test(): - object = Test.CharIndexerTest() - object["wrong"] +def test_boolean_indexer(): + """Test boolean indexers.""" + ob = Test.BooleanIndexerTest() - self.assertRaises(TypeError, test) + assert ob[True] is None + assert ob[1] is None - def test(): - object = Test.CharIndexerTest() - object["wrong"] = "wrong" + ob[0] = "false" + assert ob[0] == "false" - self.assertRaises(TypeError, test) + ob[1] = "true" + assert ob[1] == "true" - def testInt16Indexer(self): - """Test Int16 indexers.""" - object = Test.Int16IndexerTest() - max = 32767 - min = -32768 + ob[False] = "false" + assert ob[False] == "false" - self.assertTrue(object[max] == None) + ob[True] = "true" + assert ob[True] == "true" - object[max] = str(max) - self.assertTrue(object[max] == str(max)) - object[min] = str(min) - self.assertTrue(object[min] == str(min)) +def test_byte_indexer(): + """Test byte indexers.""" + ob = Test.ByteIndexerTest() + max_ = 255 + min_ = 0 - def test(): - object = Test.Int16IndexerTest() - object["wrong"] + assert ob[max_] is None - self.assertRaises(TypeError, test) + ob[max_] = str(max_) + assert ob[max_] == str(max_) - def test(): - object = Test.Int16IndexerTest() - object["wrong"] = "wrong" + ob[min_] = str(min_) + assert ob[min_] == str(min_) - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.ByteIndexerTest() + ob["wrong"] - def testInt32Indexer(self): - """Test Int32 indexers.""" - object = Test.Int32IndexerTest() - max = 2147483647 - min = -2147483648 + with pytest.raises(TypeError): + ob = Test.ByteIndexerTest() + ob["wrong"] = "wrong" - self.assertTrue(object[max] == None) - object[max] = str(max) - self.assertTrue(object[max] == str(max)) +def test_sbyte_indexer(): + """Test sbyte indexers.""" + ob = Test.SByteIndexerTest() + max_ = 127 + min_ = -128 - object[min] = str(min) - self.assertTrue(object[min] == str(min)) + assert ob[max_] is None - def test(): - object = Test.Int32IndexerTest() - object["wrong"] + ob[max_] = str(max_) + assert ob[max_] == str(max_) - self.assertRaises(TypeError, test) + ob[min_] = str(min_) + assert ob[min_] == str(min_) - def test(): - object = Test.Int32IndexerTest() - object["wrong"] = "wrong" + with pytest.raises(TypeError): + ob = Test.SByteIndexerTest() + ob["wrong"] - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.SByteIndexerTest() + ob["wrong"] = "wrong" - def testInt64Indexer(self): - """Test Int64 indexers.""" - object = Test.Int64IndexerTest() - max = long(9223372036854775807) - min = long(-9223372036854775808) - self.assertTrue(object[max] == None) +def test_char_indexer(): + """Test char indexers.""" + ob = Test.CharIndexerTest() + max_ = unichr(65535) + min_ = unichr(0) - object[max] = str(max) - self.assertTrue(object[max] == str(max)) + assert ob[max_] is None - object[min] = str(min) - self.assertTrue(object[min] == str(min)) + ob[max_] = "max_" + assert ob[max_] == "max_" - def test(): - object = Test.Int64IndexerTest() - object["wrong"] + ob[min_] = "min_" + assert ob[min_] == "min_" - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.CharIndexerTest() + ob["wrong"] - def test(): - object = Test.Int64IndexerTest() - object["wrong"] = "wrong" + with pytest.raises(TypeError): + ob = Test.CharIndexerTest() + ob["wrong"] = "wrong" - self.assertRaises(TypeError, test) - def testUInt16Indexer(self): - """Test UInt16 indexers.""" - object = Test.UInt16IndexerTest() - max = 65535 - min = 0 +def test_int16_indexer(): + """Test Int16 indexers.""" + ob = Test.Int16IndexerTest() + max_ = 32767 + min_ = -32768 - self.assertTrue(object[max] == None) + assert ob[max_] is None - object[max] = str(max) - self.assertTrue(object[max] == str(max)) + ob[max_] = str(max_) + assert ob[max_] == str(max_) - object[min] = str(min) - self.assertTrue(object[min] == str(min)) + ob[min_] = str(min_) + assert ob[min_] == str(min_) - def test(): - object = Test.UInt16IndexerTest() - object["wrong"] + with pytest.raises(TypeError): + ob = Test.Int16IndexerTest() + ob["wrong"] - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.Int16IndexerTest() + ob["wrong"] = "wrong" - def test(): - object = Test.UInt16IndexerTest() - object["wrong"] = "wrong" - self.assertRaises(TypeError, test) +def test_int32_indexer(): + """Test Int32 indexers.""" + ob = Test.Int32IndexerTest() + max_ = 2147483647 + min_ = -2147483648 - def testUInt32Indexer(self): - """Test UInt32 indexers.""" - object = Test.UInt32IndexerTest() - max = long(4294967295) - min = 0 + assert ob[max_] is None - self.assertTrue(object[max] == None) + ob[max_] = str(max_) + assert ob[max_] == str(max_) - object[max] = str(max) - self.assertTrue(object[max] == str(max)) + ob[min_] = str(min_) + assert ob[min_] == str(min_) - object[min] = str(min) - self.assertTrue(object[min] == str(min)) + with pytest.raises(TypeError): + ob = Test.Int32IndexerTest() + ob["wrong"] - def test(): - object = Test.UInt32IndexerTest() - object["wrong"] + with pytest.raises(TypeError): + ob = Test.Int32IndexerTest() + ob["wrong"] = "wrong" - self.assertRaises(TypeError, test) - def test(): - object = Test.UInt32IndexerTest() - object["wrong"] = "wrong" +def test_int64_indexer(): + """Test Int64 indexers.""" + ob = Test.Int64IndexerTest() + max_ = long(9223372036854775807) + min_ = long(-9223372036854775808) - self.assertRaises(TypeError, test) + assert ob[max_] is None - def testUInt64Indexer(self): - """Test UInt64 indexers.""" - object = Test.UInt64IndexerTest() - max = long(18446744073709551615) - min = 0 + ob[max_] = str(max_) + assert ob[max_] == str(max_) - self.assertTrue(object[max] == None) + ob[min_] = str(min_) + assert ob[min_] == str(min_) - object[max] = str(max) - self.assertTrue(object[max] == str(max)) + with pytest.raises(TypeError): + ob = Test.Int64IndexerTest() + ob["wrong"] - object[min] = str(min) - self.assertTrue(object[min] == str(min)) + with pytest.raises(TypeError): + ob = Test.Int64IndexerTest() + ob["wrong"] = "wrong" - def test(): - object = Test.UInt64IndexerTest() - object["wrong"] - self.assertRaises(TypeError, test) +def test_uint16_indexer(): + """Test UInt16 indexers.""" + ob = Test.UInt16IndexerTest() + max_ = 65535 + min_ = 0 - def test(): - object = Test.UInt64IndexerTest() - object["wrong"] = "wrong" + assert ob[max_] is None - self.assertRaises(TypeError, test) + ob[max_] = str(max_) + assert ob[max_] == str(max_) - def testSingleIndexer(self): - """Test Single indexers.""" - object = Test.SingleIndexerTest() - max = 3.402823e38 - min = -3.402823e38 + ob[min_] = str(min_) + assert ob[min_] == str(min_) - self.assertTrue(object[max] == None) + with pytest.raises(TypeError): + ob = Test.UInt16IndexerTest() + ob["wrong"] - object[max] = "max" - self.assertTrue(object[max] == "max") + with pytest.raises(TypeError): + ob = Test.UInt16IndexerTest() + ob["wrong"] = "wrong" - object[min] = "min" - self.assertTrue(object[min] == "min") - def test(): - object = Test.SingleIndexerTest() - object["wrong"] +def test_uint32_indexer(): + """Test UInt32 indexers.""" + ob = Test.UInt32IndexerTest() + max_ = long(4294967295) + min_ = 0 - self.assertRaises(TypeError, test) + assert ob[max_] is None - def test(): - object = Test.SingleIndexerTest() - object["wrong"] = "wrong" + ob[max_] = str(max_) + assert ob[max_] == str(max_) - self.assertRaises(TypeError, test) + ob[min_] = str(min_) + assert ob[min_] == str(min_) - def testDoubleIndexer(self): - """Test Double indexers.""" - object = Test.DoubleIndexerTest() - max = 1.7976931348623157e308 - min = -1.7976931348623157e308 + with pytest.raises(TypeError): + ob = Test.UInt32IndexerTest() + ob["wrong"] - self.assertTrue(object[max] == None) + with pytest.raises(TypeError): + ob = Test.UInt32IndexerTest() + ob["wrong"] = "wrong" - object[max] = "max" - self.assertTrue(object[max] == "max") - object[min] = "min" - self.assertTrue(object[min] == "min") +def test_uint64_indexer(): + """Test UInt64 indexers.""" + ob = Test.UInt64IndexerTest() + max_ = long(18446744073709551615) + min_ = 0 - def test(): - object = Test.DoubleIndexerTest() - object["wrong"] + assert ob[max_] is None - self.assertRaises(TypeError, test) + ob[max_] = str(max_) + assert ob[max_] == str(max_) - def test(): - object = Test.DoubleIndexerTest() - object["wrong"] = "wrong" + ob[min_] = str(min_) + assert ob[min_] == str(min_) - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.UInt64IndexerTest() + ob["wrong"] - def testDecimalIndexer(self): - """Test Decimal indexers.""" - object = Test.DecimalIndexerTest() + with pytest.raises(TypeError): + ob = Test.UInt64IndexerTest() + ob["wrong"] = "wrong" - from System import Decimal - max_d = Decimal.Parse("79228162514264337593543950335") - min_d = Decimal.Parse("-79228162514264337593543950335") - self.assertTrue(object[max_d] == None) +def test_single_indexer(): + """Test Single indexers.""" + ob = Test.SingleIndexerTest() + max_ = 3.402823e38 + min_ = -3.402823e38 - object[max_d] = "max" - self.assertTrue(object[max_d] == "max") + assert ob[max_] is None - object[min_d] = "min" - self.assertTrue(object[min_d] == "min") + ob[max_] = "max_" + assert ob[max_] == "max_" - def test(): - object = Test.DecimalIndexerTest() - object["wrong"] + ob[min_] = "min_" + assert ob[min_] == "min_" - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.SingleIndexerTest() + ob["wrong"] - def test(): - object = Test.DecimalIndexerTest() - object["wrong"] = "wrong" + with pytest.raises(TypeError): + ob = Test.SingleIndexerTest() + ob["wrong"] = "wrong" - self.assertRaises(TypeError, test) - def testStringIndexer(self): - """Test String indexers.""" - object = Test.StringIndexerTest() +def test_double_indexer(): + """Test Double indexers.""" + ob = Test.DoubleIndexerTest() + max_ = 1.7976931348623157e308 + min_ = -1.7976931348623157e308 - self.assertTrue(object["spam"] == None) - self.assertTrue(object[six.u("spam")] == None) + assert ob[max_] is None - object["spam"] = "spam" - self.assertTrue(object["spam"] == "spam") - self.assertTrue(object["spam"] == six.u("spam")) - self.assertTrue(object[six.u("spam")] == "spam") - self.assertTrue(object[six.u("spam")] == six.u("spam")) + ob[max_] = "max_" + assert ob[max_] == "max_" - object[six.u("eggs")] = six.u("eggs") - self.assertTrue(object["eggs"] == "eggs") - self.assertTrue(object["eggs"] == six.u("eggs")) - self.assertTrue(object[six.u("eggs")] == "eggs") - self.assertTrue(object[six.u("eggs")] == six.u("eggs")) + ob[min_] = "min_" + assert ob[min_] == "min_" - def test(): - object = Test.StringIndexerTest() - object[1] + with pytest.raises(TypeError): + ob = Test.DoubleIndexerTest() + ob["wrong"] - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.DoubleIndexerTest() + ob["wrong"] = "wrong" - def test(): - object = Test.StringIndexerTest() - object[1] = "wrong" - self.assertRaises(TypeError, test) +def test_decimal_indexer(): + """Test Decimal indexers.""" + ob = Test.DecimalIndexerTest() - def testEnumIndexer(self): - """Test enum indexers.""" - object = Test.EnumIndexerTest() + from System import Decimal + max_d = Decimal.Parse("79228162514264337593543950335") + min_d = Decimal.Parse("-79228162514264337593543950335") - key = Test.ShortEnum.One + assert ob[max_d] is None - self.assertTrue(object[key] == None) + ob[max_d] = "max_" + assert ob[max_d] == "max_" - object[key] = "spam" - self.assertTrue(object[key] == "spam") + ob[min_d] = "min_" + assert ob[min_d] == "min_" - object[key] = "eggs" - self.assertTrue(object[key] == "eggs") + with pytest.raises(TypeError): + ob = Test.DecimalIndexerTest() + ob["wrong"] - object[1] = "spam" - self.assertTrue(object[1] == "spam") + with pytest.raises(TypeError): + ob = Test.DecimalIndexerTest() + ob["wrong"] = "wrong" - def test(): - object = Test.EnumIndexerTest() - object["wrong"] - self.assertRaises(TypeError, test) +def test_string_indexer(): + """Test String indexers.""" + ob = Test.StringIndexerTest() - def test(): - object = Test.EnumIndexerTest() - object["wrong"] = "wrong" + assert ob["spam"] is None + assert ob[u"spam"] is None - self.assertRaises(TypeError, test) + ob["spam"] = "spam" + assert ob["spam"] == "spam" + assert ob["spam"] == u"spam" + assert ob[u"spam"] == "spam" + assert ob[u"spam"] == u"spam" - def testObjectIndexer(self): - """Test object indexers.""" - object = Test.ObjectIndexerTest() + ob[u"eggs"] = u"eggs" + assert ob["eggs"] == "eggs" + assert ob["eggs"] == u"eggs" + assert ob[u"eggs"] == "eggs" + assert ob[u"eggs"] == u"eggs" - from Python.Test import Spam - spam = Spam("spam") + with pytest.raises(TypeError): + ob = Test.StringIndexerTest() + ob[1] - self.assertTrue(object[spam] == None) - self.assertTrue(object["spam"] == None) - self.assertTrue(object[1] == None) - self.assertTrue(object[None] == None) + with pytest.raises(TypeError): + ob = Test.StringIndexerTest() + ob[1] = "wrong" - object[spam] = "spam" - self.assertTrue(object[spam] == "spam") - object["spam"] = "eggs" - self.assertTrue(object["spam"] == "eggs") +def test_enum_indexer(): + """Test enum indexers.""" + ob = Test.EnumIndexerTest() - object[1] = "one" - self.assertTrue(object[1] == "one") + key = Test.ShortEnum.One - object[long(1)] = "long" - self.assertTrue(object[long(1)] == "long") + assert ob[key] is None - def test(): - class eggs: - pass + ob[key] = "spam" + assert ob[key] == "spam" - key = eggs() - object = Test.ObjectIndexerTest() - object[key] = "wrong" + ob[key] = "eggs" + assert ob[key] == "eggs" - self.assertRaises(TypeError, test) + ob[1] = "spam" + assert ob[1] == "spam" - def testInterfaceIndexer(self): - """Test interface indexers.""" - object = Test.InterfaceIndexerTest() + with pytest.raises(TypeError): + ob = Test.EnumIndexerTest() + ob["wrong"] - from Python.Test import Spam - spam = Spam("spam") + with pytest.raises(TypeError): + ob = Test.EnumIndexerTest() + ob["wrong"] = "wrong" - self.assertTrue(object[spam] == None) - object[spam] = "spam" - self.assertTrue(object[spam] == "spam") +def test_object_indexer(): + """Test ob indexers.""" + ob = Test.ObjectIndexerTest() - object[spam] = "eggs" - self.assertTrue(object[spam] == "eggs") + from Python.Test import Spam + spam = Spam("spam") - def test(): - object = Test.InterfaceIndexerTest() - object["wrong"] + assert ob[spam] is None + assert ob["spam"] is None + assert ob[1] is None + assert ob[None] is None - self.assertRaises(TypeError, test) + ob[spam] = "spam" + assert ob[spam] == "spam" - def test(): - object = Test.InterfaceIndexerTest() - object["wrong"] = "wrong" + ob["spam"] = "eggs" + assert ob["spam"] == "eggs" - self.assertRaises(TypeError, test) + ob[1] = "one" + assert ob[1] == "one" - def testTypedIndexer(self): - """Test typed indexers.""" - object = Test.TypedIndexerTest() + ob[long(1)] = "long" + assert ob[long(1)] == "long" - from Python.Test import Spam - spam = Spam("spam") + with pytest.raises(TypeError): + class Eggs(object): + pass - self.assertTrue(object[spam] == None) + key = Eggs() + ob = Test.ObjectIndexerTest() + ob[key] = "wrong" - object[spam] = "spam" - self.assertTrue(object[spam] == "spam") - object[spam] = "eggs" - self.assertTrue(object[spam] == "eggs") +def test_interface_indexer(): + """Test interface indexers.""" + ob = Test.InterfaceIndexerTest() - def test(): - object = Test.TypedIndexerTest() - object["wrong"] + from Python.Test import Spam + spam = Spam("spam") - self.assertRaises(TypeError, test) + assert ob[spam] is None - def test(): - object = Test.TypedIndexerTest() - object["wrong"] = "wrong" + ob[spam] = "spam" + assert ob[spam] == "spam" - self.assertRaises(TypeError, test) + ob[spam] = "eggs" + assert ob[spam] == "eggs" - def testMultiArgIndexer(self): - """Test indexers that take multiple index arguments.""" - object = Test.MultiArgIndexerTest() + with pytest.raises(TypeError): + ob = Test.InterfaceIndexerTest() + ob["wrong"] - object[0, 1] = "zero one" - self.assertTrue(object[0, 1] == "zero one") + with pytest.raises(TypeError): + ob = Test.InterfaceIndexerTest() + ob["wrong"] = "wrong" - object[1, 9] = "one nine" - self.assertTrue(object[1, 9] == "one nine") - self.assertTrue(object[10, 50] == None) +def test_typed_indexer(): + """Test typed indexers.""" + ob = Test.TypedIndexerTest() - def test(): - object = Test.MultiArgIndexerTest() - v = object[0, "one"] + from Python.Test import Spam + spam = Spam("spam") - self.assertRaises(TypeError, test) + assert ob[spam] is None - def test(): - object = Test.MultiArgIndexerTest() - object[0, "one"] = "wrong" + ob[spam] = "spam" + assert ob[spam] == "spam" - self.assertRaises(TypeError, test) + ob[spam] = "eggs" + assert ob[spam] == "eggs" - def testMultiTypeIndexer(self): - """Test indexers that take multiple indices of different types.""" - object = Test.MultiTypeIndexerTest() - spam = Test.Spam("spam") + with pytest.raises(TypeError): + ob = Test.TypedIndexerTest() + ob["wrong"] - object[0, "one", spam] = "zero one spam" - self.assertTrue(object[0, "one", spam] == "zero one spam") + with pytest.raises(TypeError): + ob = Test.TypedIndexerTest() + ob["wrong"] = "wrong" - object[1, "nine", spam] = "one nine spam" - self.assertTrue(object[1, "nine", spam] == "one nine spam") - def test(): - object = Test.MultiTypeIndexerTest() - v = object[0, 1, spam] +def test_multi_arg_indexer(): + """Test indexers that take multiple index arguments.""" + ob = Test.MultiArgIndexerTest() - self.assertRaises(TypeError, test) + ob[0, 1] = "zero one" + assert ob[0, 1] == "zero one" - def test(): - object = Test.MultiTypeIndexerTest() - object[0, 1, spam] = "wrong" + ob[1, 9] = "one nine" + assert ob[1, 9] == "one nine" - self.assertRaises(TypeError, test) + assert ob[10, 50] is None - def testMultiDefaultKeyIndexer(self): - """Test indexers that take multiple indices with a default key arguments.""" - # default argument is 2 in the MultiDefaultKeyIndexerTest object - object = Test.MultiDefaultKeyIndexerTest() - object[0, 2] = "zero one spam" - self.assertTrue(object[0] == "zero one spam") + with pytest.raises(TypeError): + ob = Test.MultiArgIndexerTest() + _ = ob[0, "one"] - object[1] = "one nine spam" - self.assertTrue(object[1, 2] == "one nine spam") + with pytest.raises(TypeError): + ob = Test.MultiArgIndexerTest() + ob[0, "one"] = "wrong" - def testIndexerWrongKeyType(self): - """Test calling an indexer using a key of the wrong type.""" - def test(): - object = Test.PublicIndexerTest() - v = object["wrong"] +def test_multi_type_indexer(): + """Test indexers that take multiple indices of different types.""" + ob = Test.MultiTypeIndexerTest() + spam = Test.Spam("spam") - self.assertRaises(TypeError, test) + ob[0, "one", spam] = "zero one spam" + assert ob[0, "one", spam] == "zero one spam" - def test(): - object = Test.PublicIndexerTest() - object["wrong"] = "spam" + ob[1, "nine", spam] = "one nine spam" + assert ob[1, "nine", spam] == "one nine spam" - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + ob = Test.MultiTypeIndexerTest() + _ = ob[0, 1, spam] - def testIndexerWrongValueType(self): - """Test calling an indexer using a value of the wrong type.""" + with pytest.raises(TypeError): + ob = Test.MultiTypeIndexerTest() + ob[0, 1, spam] = "wrong" - def test(): - object = Test.PublicIndexerTest() - object[1] = 9993.9 - self.assertRaises(TypeError, test) +def test_multi_default_key_indexer(): + """Test indexers that take multiple indices with a default + key arguments.""" + # default argument is 2 in the MultiDefaultKeyIndexerTest object + ob = Test.MultiDefaultKeyIndexerTest() + ob[0, 2] = "zero one spam" + assert ob[0] == "zero one spam" - def testUnboundIndexer(self): - """Test calling an unbound indexer.""" - object = Test.PublicIndexerTest() + ob[1] = "one nine spam" + assert ob[1, 2] == "one nine spam" - Test.PublicIndexerTest.__setitem__(object, 0, "zero") - self.assertTrue(object[0] == "zero") - Test.PublicIndexerTest.__setitem__(object, 1, "one") - self.assertTrue(object[1] == "one") +def test_indexer_wrong_key_type(): + """Test calling an indexer using a key of the wrong type.""" - self.assertTrue(object[10] == None) + with pytest.raises(TypeError): + ob = Test.PublicIndexerTest() + _ = ob["wrong"] - def testIndexerAbuse(self): - """Test indexer abuse.""" - _class = Test.PublicIndexerTest - object = Test.PublicIndexerTest() + with pytest.raises(TypeError): + ob = Test.PublicIndexerTest() + ob["wrong"] = "spam" - def test(): - del _class.__getitem__ - self.assertRaises(AttributeError, test) +def test_indexer_wrong_value_type(): + """Test calling an indexer using a value of the wrong type.""" - def test(): - del object.__getitem__ + with pytest.raises(TypeError): + ob = Test.PublicIndexerTest() + ob[1] = 9993.9 - self.assertRaises(AttributeError, test) - def test(): - del _class.__setitem__ +def test_unbound_indexer(): + """Test calling an unbound indexer.""" + ob = Test.PublicIndexerTest() - self.assertRaises(AttributeError, test) + Test.PublicIndexerTest.__setitem__(ob, 0, "zero") + assert ob[0] == "zero" - def test(): - del object.__setitem__ + Test.PublicIndexerTest.__setitem__(ob, 1, "one") + assert ob[1] == "one" - self.assertRaises(AttributeError, test) + assert ob[10] is None -def test_suite(): - return unittest.makeSuite(IndexerTests) +def test_indexer_abuse(): + """Test indexer abuse.""" + _class = Test.PublicIndexerTest + ob = Test.PublicIndexerTest() + with pytest.raises(AttributeError): + del _class.__getitem__ -def main(): - unittest.TextTestRunner().run(test_suite()) + with pytest.raises(AttributeError): + del ob.__getitem__ + with pytest.raises(AttributeError): + del _class.__setitem__ -if __name__ == '__main__': - main() + with pytest.raises(AttributeError): + del ob.__setitem__ diff --git a/src/tests/test_interface.py b/src/tests/test_interface.py index 1e495fe25..997f17264 100644 --- a/src/tests/test_interface.py +++ b/src/tests/test_interface.py @@ -1,84 +1,69 @@ -from Python.Test import InterfaceTest -import sys, os, string, unittest, types -import Python.Test as Test -import System -import six - -if six.PY3: - DictProxyType = type(object.__dict__) -else: - DictProxyType = types.DictProxyType +# -*- coding: utf-8 -*- +"""Test CLR interface support.""" -class InterfaceTests(unittest.TestCase): - """Test CLR interface support.""" - - def testInterfaceStandardAttrs(self): - """Test standard class attributes.""" - from Python.Test import IPublicInterface as ip - self.assertTrue(ip.__name__ == 'IPublicInterface') - self.assertTrue(ip.__module__ == 'Python.Test') - self.assertTrue(type(ip.__dict__) == DictProxyType) +import Python.Test as Test +import pytest - def testGlobalInterfaceVisibility(self): - """Test visibility of module-level interfaces.""" - from Python.Test import IPublicInterface - self.assertTrue(IPublicInterface.__name__ == 'IPublicInterface') +from ._compat import DictProxyType - def test(): - from Python.Test import IInternalInterface - self.assertRaises(ImportError, test) +def test_interface_standard_attrs(): + """Test standard class attributes.""" + from Python.Test import IPublicInterface - def test(): - i = Test.IInternalInterface + assert IPublicInterface.__name__ == 'IPublicInterface' + assert IPublicInterface.__module__ == 'Python.Test' + assert isinstance(IPublicInterface.__dict__, DictProxyType) - self.assertRaises(AttributeError, test) - def testNestedInterfaceVisibility(self): - """Test visibility of nested interfaces.""" - ob = InterfaceTest.IPublic - self.assertTrue(ob.__name__ == 'IPublic') +def test_global_interface_visibility(): + """Test visibility of module-level interfaces.""" + from Python.Test import IPublicInterface - ob = InterfaceTest.IProtected - self.assertTrue(ob.__name__ == 'IProtected') + assert IPublicInterface.__name__ == 'IPublicInterface' - def test(): - ob = InterfaceTest.IInternal + with pytest.raises(ImportError): + from Python.Test import IInternalInterface + _ = IInternalInterface - self.assertRaises(AttributeError, test) + with pytest.raises(AttributeError): + _ = Test.IInternalInterface - def test(): - ob = InterfaceTest.IPrivate - self.assertRaises(AttributeError, test) +def test_nested_interface_visibility(): + """Test visibility of nested interfaces.""" + from Python.Test import InterfaceTest - def testExplicitCastToInterface(self): - """Test explicit cast to an interface.""" - ob = InterfaceTest() - self.assertTrue(type(ob).__name__ == 'InterfaceTest') - self.assertTrue(hasattr(ob, 'HelloProperty')) + ob = InterfaceTest.IPublic + assert ob.__name__ == 'IPublic' - i1 = Test.ISayHello1(ob) - self.assertTrue(type(i1).__name__ == 'ISayHello1') - self.assertTrue(hasattr(i1, 'SayHello')) - self.assertTrue(i1.SayHello() == 'hello 1') - self.assertFalse(hasattr(i1, 'HelloProperty')) + ob = InterfaceTest.IProtected + assert ob.__name__ == 'IProtected' - i2 = Test.ISayHello2(ob) - self.assertTrue(type(i2).__name__ == 'ISayHello2') - self.assertTrue(i2.SayHello() == 'hello 2') - self.assertTrue(hasattr(i2, 'SayHello')) - self.assertFalse(hasattr(i2, 'HelloProperty')) + with pytest.raises(AttributeError): + _ = InterfaceTest.IInternal + with pytest.raises(AttributeError): + _ = InterfaceTest.IPrivate -def test_suite(): - return unittest.makeSuite(InterfaceTests) +def test_explicit_cast_to_interface(): + """Test explicit cast to an interface.""" + from Python.Test import InterfaceTest -def main(): - unittest.TextTestRunner().run(test_suite()) + ob = InterfaceTest() + assert type(ob).__name__ == 'InterfaceTest' + assert hasattr(ob, 'HelloProperty') + i1 = Test.ISayHello1(ob) + assert type(i1).__name__ == 'ISayHello1' + assert hasattr(i1, 'SayHello') + assert i1.SayHello() == 'hello 1' + assert not hasattr(i1, 'HelloProperty') -if __name__ == '__main__': - main() + i2 = Test.ISayHello2(ob) + assert type(i2).__name__ == 'ISayHello2' + assert i2.SayHello() == 'hello 2' + assert hasattr(i2, 'SayHello') + assert not hasattr(i2, 'HelloProperty') diff --git a/src/tests/test_method.py b/src/tests/test_method.py index 4728d13e4..ad182678d 100644 --- a/src/tests/test_method.py +++ b/src/tests/test_method.py @@ -1,794 +1,834 @@ -import sys, os, string, unittest, types -import clr +# -*- coding: utf-8 -*- -clr.AddReference("Python.Test") +"""Test CLR method support.""" -from Python.Test import MethodTest, MethodTestSub import System -import six +import pytest +from Python.Test import MethodTest -if six.PY3: - long = int - unichr = chr +from ._compat import PY2, long, unichr -class MethodTests(unittest.TestCase): - """Test CLR method support.""" +def test_instance_method_descriptor(): + """Test instance method descriptor behavior.""" - def testInstanceMethodDescriptor(self): - """Test instance method descriptor behavior.""" + with pytest.raises(AttributeError): + MethodTest().PublicMethod = 0 - def test(): - MethodTest().PublicMethod = 0 + with pytest.raises(AttributeError): + MethodTest.PublicMethod = 0 - self.assertRaises(AttributeError, test) + with pytest.raises(AttributeError): + del MethodTest().PublicMethod - def test(): - MethodTest.PublicMethod = 0 + with pytest.raises(AttributeError): + del MethodTest.PublicMethod - self.assertRaises(AttributeError, test) - def test(): - del MethodTest().PublicMethod +def test_static_method_descriptor(): + """Test static method descriptor behavior.""" - self.assertRaises(AttributeError, test) + with pytest.raises(AttributeError): + MethodTest().PublicStaticMethod = 0 - def test(): - del MethodTest.PublicMethod + with pytest.raises(AttributeError): + MethodTest.PublicStaticMethod = 0 - self.assertRaises(AttributeError, test) + with pytest.raises(AttributeError): + del MethodTest().PublicStaticMethod - def testStaticMethodDescriptor(self): - """Test static method descriptor behavior.""" + with pytest.raises(AttributeError): + del MethodTest.PublicStaticMethod - def test(): - MethodTest().PublicStaticMethod = 0 - self.assertRaises(AttributeError, test) +def test_public_instance_method(): + """Test public instance method visibility.""" + ob = MethodTest() + assert ob.PublicMethod() == "public" - def test(): - MethodTest.PublicStaticMethod = 0 - self.assertRaises(AttributeError, test) +def test_public_static_method(): + """Test public static method visibility.""" + ob = MethodTest() + assert MethodTest.PublicStaticMethod() == "public static" + assert ob.PublicStaticMethod() == "public static" - def test(): - del MethodTest().PublicStaticMethod - self.assertRaises(AttributeError, test) +def test_protected_instance_method(): + """Test protected instance method visibility.""" + ob = MethodTest() + assert ob.ProtectedMethod() == "protected" - def test(): - del MethodTest.PublicStaticMethod - self.assertRaises(AttributeError, test) +def test_protected_static_method(): + """Test protected static method visibility.""" + ob = MethodTest() + result = "protected static" + assert MethodTest.ProtectedStaticMethod() == result + assert ob.ProtectedStaticMethod() == result - def testPublicInstanceMethod(self): - """Test public instance method visibility.""" - object = MethodTest(); - self.assertTrue(object.PublicMethod() == "public") - def testPublicStaticMethod(self): - """Test public static method visibility.""" - object = MethodTest(); - self.assertTrue(MethodTest.PublicStaticMethod() == "public static") - self.assertTrue(object.PublicStaticMethod() == "public static") +def test_internal_method(): + """Test internal method visibility.""" - def testProtectedInstanceMethod(self): - """Test protected instance method visibility.""" - object = MethodTest(); - self.assertTrue(object.ProtectedMethod() == "protected") + with pytest.raises(AttributeError): + _ = MethodTest().InternalMethod - def testProtectedStaticMethod(self): - """Test protected static method visibility.""" - object = MethodTest(); - result = "protected static" - self.assertTrue(MethodTest.ProtectedStaticMethod() == result) - self.assertTrue(object.ProtectedStaticMethod() == result) + with pytest.raises(AttributeError): + _ = MethodTest.InternalMethod - def testInternalMethod(self): - """Test internal method visibility.""" + with pytest.raises(AttributeError): + _ = MethodTest().InternalStaticMethod - def test(): - f = MethodTest().InternalMethod + with pytest.raises(AttributeError): + _ = MethodTest.InternalStaticMethod - self.assertRaises(AttributeError, test) - def test(): - f = MethodTest.InternalMethod +def test_private_method(): + """Test private method visibility.""" - self.assertRaises(AttributeError, test) + with pytest.raises(AttributeError): + _ = MethodTest().PrivateMethod - def test(): - f = MethodTest().InternalStaticMethod + with pytest.raises(AttributeError): + _ = MethodTest.PrivateMethod - self.assertRaises(AttributeError, test) + with pytest.raises(AttributeError): + _ = MethodTest().PrivateStaticMethod - def test(): - f = MethodTest.InternalStaticMethod + with pytest.raises(AttributeError): + _ = MethodTest.PrivateStaticMethod - self.assertRaises(AttributeError, test) - def testPrivateMethod(self): - """Test private method visibility.""" +def test_unbound_managed_method_call(): + """Test calling unbound managed methods.""" + from Python.Test import MethodTestSub - def test(): - f = MethodTest().PrivateMethod + ob = MethodTest() + assert MethodTest.PublicMethod(ob) == "public" - self.assertRaises(AttributeError, test) + with pytest.raises(TypeError): + MethodTest.PublicMethod() - def test(): - f = MethodTest.PrivateMethod + ob = MethodTestSub() + assert MethodTestSub.PublicMethod(ob) == "public" + assert MethodTestSub.PublicMethod(ob, "echo") == "echo" - self.assertRaises(AttributeError, test) + with pytest.raises(TypeError): + MethodTestSub.PublicMethod("echo") - def test(): - f = MethodTest().PrivateStaticMethod - self.assertRaises(AttributeError, test) +def test_overloaded_method_inheritance(): + """Test that overloads are inherited properly.""" + from Python.Test import MethodTestSub - def test(): - f = MethodTest.PrivateStaticMethod + ob = MethodTest() + assert ob.PublicMethod() == "public" - self.assertRaises(AttributeError, test) + with pytest.raises(TypeError): + ob = MethodTest() + ob.PublicMethod("echo") - def testUnboundManagedMethodCall(self): - """Test calling unbound managed methods.""" + ob = MethodTestSub() + assert ob.PublicMethod() == "public" - object = MethodTest() - self.assertTrue(MethodTest.PublicMethod(object) == "public") + assert ob.PublicMethod("echo") == "echo" - def test(): - MethodTest.PublicMethod() - self.assertRaises(TypeError, test) +def test_method_descriptor_abuse(): + """Test method descriptor abuse.""" + desc = MethodTest.__dict__['PublicMethod'] - object = MethodTestSub(); - self.assertTrue(MethodTestSub.PublicMethod(object) == "public") - self.assertTrue(MethodTestSub.PublicMethod(object, "echo") == "echo") + with pytest.raises(TypeError): + desc.__get__(0, 0) - def test(): - MethodTestSub.PublicMethod("echo") + with pytest.raises(AttributeError): + desc.__set__(0, 0) - self.assertRaises(TypeError, test) - def testOverloadedMethodInheritance(self): - """Test that overloads are inherited properly.""" +def test_method_docstrings(): + """Test standard method docstring generation""" + method = MethodTest.GetType + value = 'System.Type GetType()' + assert method.__doc__ == value - object = MethodTest() - self.assertTrue(object.PublicMethod() == "public") - def test(): - object = MethodTest() - object.PublicMethod("echo") +# ====================================================================== +# Tests of specific argument and result conversion scenarios +# ====================================================================== +def test_method_call_enum_conversion(): + """Test enum conversion in method call.""" + from System import TypeCode - self.assertRaises(TypeError, test) + ob = MethodTest() + r = ob.TestEnumConversion(TypeCode.Int32) + assert r == TypeCode.Int32 - object = MethodTestSub(); - self.assertTrue(object.PublicMethod() == "public") - self.assertTrue(object.PublicMethod("echo") == "echo") +def test_method_call_flags_conversion(): + """Test flags conversion in method call.""" + from System.IO import FileAccess - def testMethodDescriptorAbuse(self): - """Test method descriptor abuse.""" - desc = MethodTest.__dict__['PublicMethod'] + ob = MethodTest() + flags = FileAccess.Read | FileAccess.Write + r = ob.TestFlagsConversion(flags) + assert r == flags - def test(): - desc.__get__(0, 0) - self.assertRaises(TypeError, test) +def test_method_call_struct_conversion(): + """Test struct conversion in method call.""" + from System import Guid - def test(): - desc.__set__(0, 0) + ob = MethodTest() + guid = Guid.NewGuid() + temp = guid.ToString() + r = ob.TestStructConversion(guid) + assert r.ToString() == temp - self.assertRaises(AttributeError, test) - def testMethodDocstrings(self): - """Test standard method docstring generation""" - method = MethodTest.GetType - value = 'System.Type GetType()' - self.assertTrue(method.__doc__ == value) +def test_subclass_instance_conversion(): + """Test subclass instance conversion in method call.""" - # ====================================================================== - # Tests of specific argument and result conversion scenarios - # ====================================================================== + class TestSubException(System.Exception): + pass - def testMethodCallEnumConversion(self): - """Test enum conversion in method call.""" - from System import TypeCode + ob = MethodTest() + instance = TestSubException() + result = ob.TestSubclassConversion(instance) + assert isinstance(result, System.Exception) - object = MethodTest() - r = object.TestEnumConversion(TypeCode.Int32) - self.assertTrue(r == TypeCode.Int32) - def testMethodCallFlagsConversion(self): - """Test flags conversion in method call.""" - from System.IO import FileAccess +def test_null_array_conversion(): + """Test null array conversion in method call.""" + ob = MethodTest() + r = ob.TestNullArrayConversion(None) + assert r is None - object = MethodTest() - flags = FileAccess.Read | FileAccess.Write - r = object.TestFlagsConversion(flags) - self.assertTrue(r == flags) - def testMethodCallStructConversion(self): - """Test struct conversion in method call.""" - from System import Guid - - object = MethodTest() - guid = Guid.NewGuid() - temp = guid.ToString() - r = object.TestStructConversion(guid) - self.assertTrue(r.ToString() == temp) - - def testSubclassInstanceConversion(self): - """Test subclass instance conversion in method call.""" - - class TestSubException(System.Exception): - pass - - object = MethodTest() - instance = TestSubException() - result = object.TestSubclassConversion(instance) - self.assertTrue(isinstance(result, System.Exception)) - - def testNullArrayConversion(self): - """Test null array conversion in method call.""" - from System import Type - - object = MethodTest() - r = object.TestNullArrayConversion(None) - self.assertTrue(r == None) - - def testStringParamsArgs(self): - """Test use of string params.""" - result = MethodTest.TestStringParamsArg('one', 'two', 'three') - self.assertEqual(result.Length, 3) - self.assertEqual(len(result), 3, result) - self.assertTrue(result[0] == 'one') - self.assertTrue(result[1] == 'two') - self.assertTrue(result[2] == 'three') - - result = MethodTest.TestStringParamsArg(['one', 'two', 'three']) - self.assertTrue(len(result) == 3) - self.assertTrue(result[0] == 'one') - self.assertTrue(result[1] == 'two') - self.assertTrue(result[2] == 'three') - - def testObjectParamsArgs(self): - """Test use of object params.""" - result = MethodTest.TestObjectParamsArg('one', 'two', 'three') - self.assertEqual(len(result), 3, result) - self.assertTrue(result[0] == 'one') - self.assertTrue(result[1] == 'two') - self.assertTrue(result[2] == 'three') - - result = MethodTest.TestObjectParamsArg(['one', 'two', 'three']) - self.assertEqual(len(result), 3, result) - self.assertTrue(result[0] == 'one') - self.assertTrue(result[1] == 'two') - self.assertTrue(result[2] == 'three') - - def testValueParamsArgs(self): - """Test use of value type params.""" - result = MethodTest.TestValueParamsArg(1, 2, 3) - self.assertEqual(len(result), 3) - self.assertTrue(result[0] == 1) - self.assertTrue(result[1] == 2) - self.assertTrue(result[2] == 3) - - result = MethodTest.TestValueParamsArg([1, 2, 3]) - self.assertEqual(len(result), 3) - self.assertTrue(result[0] == 1) - self.assertTrue(result[1] == 2) - self.assertTrue(result[2] == 3) - - def testNonParamsArrayInLastPlace(self): - """Test overload resolution with of non-"params" array as last parameter.""" - result = MethodTest.TestNonParamsArrayInLastPlace(1, 2, 3) - self.assertTrue(result) - - def testStringOutParams(self): - """Test use of string out-parameters.""" - result = MethodTest.TestStringOutParams("hi", "there") - self.assertTrue(type(result) == type(())) - self.assertEqual(len(result), 2) - self.assertTrue(result[0] == True) - self.assertTrue(result[1] == "output string") - - result = MethodTest.TestStringOutParams("hi", None) - self.assertTrue(type(result) == type(())) - self.assertEqual(len(result), 2) - self.assertTrue(result[0] == True) - self.assertTrue(result[1] == "output string") - - def testStringRefParams(self): - """Test use of string byref parameters.""" - result = MethodTest.TestStringRefParams("hi", "there") - self.assertTrue(type(result) == type(())) - self.assertEqual(len(result), 2) - self.assertTrue(result[0] == True) - self.assertTrue(result[1] == "output string") - - result = MethodTest.TestStringRefParams("hi", None) - self.assertTrue(type(result) == type(())) - self.assertEqual(len(result), 2) - self.assertTrue(result[0] == True) - self.assertTrue(result[1] == "output string") - - def testValueOutParams(self): - """Test use of value type out-parameters.""" - result = MethodTest.TestValueOutParams("hi", 1) - self.assertTrue(type(result) == type(())) - self.assertEqual(len(result), 2) - self.assertTrue(result[0] == True) - self.assertTrue(result[1] == 42) - - def test(): - MethodTest.TestValueOutParams("hi", None) - - # None cannot be converted to a value type like int, long, etc. - self.assertRaises(TypeError, test) - - def testValueRefParams(self): - """Test use of value type byref parameters.""" - result = MethodTest.TestValueRefParams("hi", 1) - self.assertTrue(type(result) == type(())) - self.assertEqual(len(result), 2) - self.assertTrue(result[0] == True) - self.assertTrue(result[1] == 42) - - def test(): - MethodTest.TestValueRefParams("hi", None) - - # None cannot be converted to a value type like int, long, etc. - self.assertRaises(TypeError, test) - - def testObjectOutParams(self): - """Test use of object out-parameters.""" - result = MethodTest.TestObjectOutParams("hi", MethodTest()) - self.assertTrue(type(result) == type(())) - self.assertTrue(len(result) == 2) - self.assertTrue(result[0] == True) - self.assertTrue(isinstance(result[1], System.Exception)) - - result = MethodTest.TestObjectOutParams("hi", None) - self.assertTrue(type(result) == type(())) - self.assertEqual(len(result), 2) - self.assertTrue(result[0] == True) - self.assertTrue(isinstance(result[1], System.Exception)) - - def testObjectRefParams(self): - """Test use of object byref parameters.""" - result = MethodTest.TestObjectRefParams("hi", MethodTest()) - self.assertTrue(type(result) == type(())) - self.assertEqual(len(result), 2) - self.assertTrue(result[0] == True) - self.assertTrue(isinstance(result[1], System.Exception)) - - result = MethodTest.TestObjectRefParams("hi", None) - self.assertTrue(type(result) == type(())) - self.assertEqual(len(result), 2) - self.assertTrue(result[0] == True) - self.assertTrue(isinstance(result[1], System.Exception)) - - def testStructOutParams(self): - """Test use of struct out-parameters.""" - result = MethodTest.TestStructOutParams("hi", System.Guid.NewGuid()) - self.assertTrue(type(result) == type(())) - self.assertEqual(len(result), 2) - self.assertTrue(result[0] == True) - self.assertTrue(isinstance(result[1], System.Guid)) - - def test(): - MethodTest.TestValueRefParams("hi", None) - - # None cannot be converted to a value type like a struct - self.assertRaises(TypeError, test) - - def testStructRefParams(self): - """Test use of struct byref parameters.""" - result = MethodTest.TestStructRefParams("hi", System.Guid.NewGuid()) - self.assertTrue(type(result) == type(())) - self.assertTrue(len(result) == 2) - self.assertTrue(result[0] == True) - self.assertTrue(isinstance(result[1], System.Guid)) - - def test(): - MethodTest.TestValueRefParams("hi", None) - - # None cannot be converted to a value type like a struct - self.assertRaises(TypeError, test) - - def testVoidSingleOutParam(self): - """Test void method with single out-parameter.""" - result = MethodTest.TestVoidSingleOutParam(9) - self.assertTrue(result == 42) - - def test(): - MethodTest.TestVoidSingleOutParam(None) - - # None cannot be converted to a value type - self.assertRaises(TypeError, test) - - def testVoidSingleRefParam(self): - """Test void method with single ref-parameter.""" - result = MethodTest.TestVoidSingleRefParam(9) - self.assertTrue(result == 42) - - def test(): - MethodTest.TestVoidSingleRefParam(None) - - # None cannot be converted to a value type - self.assertRaises(TypeError, test) - - def testSingleDefaultParam(self): - """Test void method with single ref-parameter.""" - result = MethodTest.TestSingleDefaultParam() - self.assertTrue(result == 5) - - def testOneArgAndTwoDefaultParam(self): - """Test void method with single ref-parameter.""" - result = MethodTest.TestOneArgAndTwoDefaultParam(11) - self.assertTrue(result == 22) - - result = MethodTest.TestOneArgAndTwoDefaultParam(15) - self.assertTrue(result == 26) - - result = MethodTest.TestOneArgAndTwoDefaultParam(20) - self.assertTrue(result == 31) - - def testTwoDefaultParam(self): - """Test void method with single ref-parameter.""" - result = MethodTest.TestTwoDefaultParam() - self.assertTrue(result == 11) - - def testExplicitSelectionWithOutModifier(self): - """Check explicit overload selection with out modifiers.""" - refstr = System.String("").GetType().MakeByRefType() - result = MethodTest.TestStringOutParams.__overloads__[str, refstr]( - "hi", "there" - ) - self.assertTrue(type(result) == type(())) - self.assertTrue(len(result) == 2) - self.assertTrue(result[0] == True) - self.assertTrue(result[1] == "output string") - - result = MethodTest.TestStringOutParams.__overloads__[str, refstr]( - "hi", None - ) - self.assertTrue(type(result) == type(())) - self.assertTrue(len(result) == 2) - self.assertTrue(result[0] == True) - self.assertTrue(result[1] == "output string") - - def testExplicitSelectionWithRefModifier(self): - """Check explicit overload selection with ref modifiers.""" - refstr = System.String("").GetType().MakeByRefType() - result = MethodTest.TestStringRefParams.__overloads__[str, refstr]( - "hi", "there" - ) - self.assertTrue(type(result) == type(())) - self.assertTrue(len(result) == 2) - self.assertTrue(result[0] == True) - self.assertTrue(result[1] == "output string") - - result = MethodTest.TestStringRefParams.__overloads__[str, refstr]( - "hi", None - ) - self.assertTrue(type(result) == type(())) - self.assertTrue(len(result) == 2) - self.assertTrue(result[0] == True) - self.assertTrue(result[1] == "output string") - - def testExplicitOverloadSelection(self): - """Check explicit overload selection using [] syntax.""" - from Python.Test import ISayHello1, InterfaceTest, ShortEnum - from System import Array - inst = InterfaceTest() - - value = MethodTest.Overloaded.__overloads__[System.Boolean](True) - self.assertTrue(value == True) - - value = MethodTest.Overloaded.__overloads__[bool](True) - self.assertTrue(value == True) - - value = MethodTest.Overloaded.__overloads__[System.Byte](255) - self.assertTrue(value == 255) - - value = MethodTest.Overloaded.__overloads__[System.SByte](127) - self.assertTrue(value == 127) - - value = MethodTest.Overloaded.__overloads__[System.Char](six.u('A')) - self.assertTrue(value == six.u('A')) - - value = MethodTest.Overloaded.__overloads__[System.Char](65535) - self.assertTrue(value == unichr(65535)) - - value = MethodTest.Overloaded.__overloads__[System.Int16](32767) - self.assertTrue(value == 32767) - - value = MethodTest.Overloaded.__overloads__[System.Int32](2147483647) - self.assertTrue(value == 2147483647) - - value = MethodTest.Overloaded.__overloads__[int](2147483647) - self.assertTrue(value == 2147483647) - - value = MethodTest.Overloaded.__overloads__[System.Int64]( - long(9223372036854775807) - ) - self.assertTrue(value == long(9223372036854775807)) - - # Python 3 has no explicit long type, use System.Int64 instead - if not six.PY3: - value = MethodTest.Overloaded.__overloads__[long]( - long(9223372036854775807) - ) - self.assertTrue(value == long(9223372036854775807)) - - value = MethodTest.Overloaded.__overloads__[System.UInt16](65000) - self.assertTrue(value == 65000) - - value = MethodTest.Overloaded.__overloads__[System.UInt32](long(4294967295)) - self.assertTrue(value == long(4294967295)) - - value = MethodTest.Overloaded.__overloads__[System.UInt64]( - long(18446744073709551615) - ) - self.assertTrue(value == long(18446744073709551615)) - - value = MethodTest.Overloaded.__overloads__[System.Single](3.402823e38) - self.assertTrue(value == 3.402823e38) - - value = MethodTest.Overloaded.__overloads__[System.Double]( - 1.7976931348623157e308 - ) - self.assertTrue(value == 1.7976931348623157e308) - - value = MethodTest.Overloaded.__overloads__[float]( - 1.7976931348623157e308 - ) - self.assertTrue(value == 1.7976931348623157e308) - - value = MethodTest.Overloaded.__overloads__[System.Decimal]( - System.Decimal.One - ) - self.assertTrue(value == System.Decimal.One) - - value = MethodTest.Overloaded.__overloads__[System.String]("spam") - self.assertTrue(value == "spam") - - value = MethodTest.Overloaded.__overloads__[str]("spam") - self.assertTrue(value == "spam") - - value = MethodTest.Overloaded.__overloads__[ShortEnum](ShortEnum.Zero) - self.assertTrue(value == ShortEnum.Zero) - - value = MethodTest.Overloaded.__overloads__[System.Object](inst) - self.assertTrue(value.__class__ == inst.__class__) - - value = MethodTest.Overloaded.__overloads__[InterfaceTest](inst) - self.assertTrue(value.__class__ == inst.__class__) - - value = MethodTest.Overloaded.__overloads__[ISayHello1](inst) - self.assertTrue(value.__class__ == inst.__class__) - - atype = Array[System.Object] - value = MethodTest.Overloaded.__overloads__[str, int, atype]( - "one", 1, atype([1, 2, 3]) - ) - self.assertTrue(value == 3) - - value = MethodTest.Overloaded.__overloads__[str, int]("one", 1) - self.assertTrue(value == 1) - - value = MethodTest.Overloaded.__overloads__[int, str](1, "one") - self.assertTrue(value == 1) - - def testOverloadSelectionWithArrayTypes(self): - """Check overload selection using array types.""" - from Python.Test import ISayHello1, InterfaceTest, ShortEnum - from System import Array - inst = InterfaceTest() - - vtype = Array[System.Boolean] - input = vtype([True, True]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == True) - self.assertTrue(value[1] == True) - - vtype = Array[bool] - input = vtype([True, True]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == True) - self.assertTrue(value[1] == True) - - vtype = Array[System.Byte] - input = vtype([0, 255]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == 255) - - vtype = Array[System.SByte] - input = vtype([0, 127]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == 127) - - vtype = Array[System.Char] - input = vtype([six.u('A'), six.u('Z')]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == six.u('A')) - self.assertTrue(value[1] == six.u('Z')) - - vtype = Array[System.Char] - input = vtype([0, 65535]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == unichr(0)) - self.assertTrue(value[1] == unichr(65535)) - - vtype = Array[System.Int16] - input = vtype([0, 32767]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == 32767) - - vtype = Array[System.Int32] - input = vtype([0, 2147483647]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == 2147483647) - - vtype = Array[int] - input = vtype([0, 2147483647]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == 2147483647) - - vtype = Array[System.Int64] - input = vtype([0, long(9223372036854775807)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == long(9223372036854775807)) - - # Python 3 has no explicit long type, use System.Int64 instead - if not six.PY3: - vtype = Array[long] - input = vtype([0, long(9223372036854775807)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == long(9223372036854775807)) - - vtype = Array[System.UInt16] - input = vtype([0, 65000]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == 65000) - - vtype = Array[System.UInt32] - input = vtype([0, long(4294967295)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == long(4294967295)) - - vtype = Array[System.UInt64] - input = vtype([0, long(18446744073709551615)]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == 0) - self.assertTrue(value[1] == long(18446744073709551615)) - - vtype = Array[System.Single] - input = vtype([0.0, 3.402823e38]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == 0.0) - self.assertTrue(value[1] == 3.402823e38) - - vtype = Array[System.Double] - input = vtype([0.0, 1.7976931348623157e308]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == 0.0) - self.assertTrue(value[1] == 1.7976931348623157e308) - - vtype = Array[float] - input = vtype([0.0, 1.7976931348623157e308]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == 0.0) - self.assertTrue(value[1] == 1.7976931348623157e308) - - vtype = Array[System.Decimal] - input = vtype([System.Decimal.Zero, System.Decimal.One]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == System.Decimal.Zero) - self.assertTrue(value[1] == System.Decimal.One) - - vtype = Array[System.String] - input = vtype(["one", "two"]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == "one") - self.assertTrue(value[1] == "two") - - vtype = Array[str] - input = vtype(["one", "two"]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == "one") - self.assertTrue(value[1] == "two") - - vtype = Array[ShortEnum] - input = vtype([ShortEnum.Zero, ShortEnum.One]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0] == ShortEnum.Zero) - self.assertTrue(value[1] == ShortEnum.One) - - vtype = Array[System.Object] - input = vtype([inst, inst]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].__class__ == inst.__class__) - self.assertTrue(value[1].__class__ == inst.__class__) - - vtype = Array[InterfaceTest] - input = vtype([inst, inst]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].__class__ == inst.__class__) - self.assertTrue(value[1].__class__ == inst.__class__) - - vtype = Array[ISayHello1] - input = vtype([inst, inst]) - value = MethodTest.Overloaded.__overloads__[vtype](input) - self.assertTrue(value[0].__class__ == inst.__class__) - self.assertTrue(value[1].__class__ == inst.__class__) - - def testExplicitOverloadSelectionFailure(self): - """Check that overload selection fails correctly.""" - - def test(): - value = MethodTest.Overloaded.__overloads__[System.Type](True) - - self.assertRaises(TypeError, test) - - def test(): - value = MethodTest.Overloaded.__overloads__[int, int](1, 1) - - self.assertRaises(TypeError, test) - - def test(): - value = MethodTest.Overloaded.__overloads__[str, int, int]( - "", 1, 1 - ) - - self.assertRaises(TypeError, test) - - def test(): - value = MethodTest.Overloaded.__overloads__[int, long](1) - - self.assertRaises(TypeError, test) - - def testWeCanBindToEncodingGetString(self): - """Check that we can bind to the Encoding.GetString method with variables.""" - - from System.Text import Encoding - from System.IO import MemoryStream - myBytes = Encoding.UTF8.GetBytes('Some testing string') - stream = MemoryStream() - stream.Write(myBytes, 0, myBytes.Length) - stream.Position = 0 - - buff = System.Array.CreateInstance(System.Byte, 3) - buff.Initialize() - data = [] - read = 1 - - while read > 0: - read, _ = stream.Read(buff, 0, buff.Length) - temp = Encoding.UTF8.GetString(buff, 0, read) - data.append(temp) - - data = ''.join(data) - self.assertEqual(data, 'Some testing string') - -def test_suite(): - return unittest.makeSuite(MethodTests) - - -def main(): - unittest.TextTestRunner().run(test_suite()) - - -if __name__ == '__main__': - main() +def test_string_params_args(): + """Test use of string params.""" + result = MethodTest.TestStringParamsArg('one', 'two', 'three') + assert result.Length == 3 + assert len(result) == 3, result + assert result[0] == 'one' + assert result[1] == 'two' + assert result[2] == 'three' + + result = MethodTest.TestStringParamsArg(['one', 'two', 'three']) + assert len(result) == 3 + assert result[0] == 'one' + assert result[1] == 'two' + assert result[2] == 'three' + + +def test_object_params_args(): + """Test use of object params.""" + result = MethodTest.TestObjectParamsArg('one', 'two', 'three') + assert len(result) == 3, result + assert result[0] == 'one' + assert result[1] == 'two' + assert result[2] == 'three' + + result = MethodTest.TestObjectParamsArg(['one', 'two', 'three']) + assert len(result) == 3, result + assert result[0] == 'one' + assert result[1] == 'two' + assert result[2] == 'three' + + +def test_value_params_args(): + """Test use of value type params.""" + result = MethodTest.TestValueParamsArg(1, 2, 3) + assert len(result) == 3 + assert result[0] == 1 + assert result[1] == 2 + assert result[2] == 3 + + result = MethodTest.TestValueParamsArg([1, 2, 3]) + assert len(result) == 3 + assert result[0] == 1 + assert result[1] == 2 + assert result[2] == 3 + + +def test_non_params_array_in_last_place(): + """Test overload resolution with of non-"params" array as + last parameter.""" + result = MethodTest.TestNonParamsArrayInLastPlace(1, 2, 3) + assert result + + +def test_string_out_params(): + """Test use of string out-parameters.""" + result = MethodTest.TestStringOutParams("hi", "there") + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert result[1] == "output string" + + result = MethodTest.TestStringOutParams("hi", None) + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert result[1] == "output string" + + +def test_string_ref_params(): + """Test use of string byref parameters.""" + result = MethodTest.TestStringRefParams("hi", "there") + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert result[1] == "output string" + + result = MethodTest.TestStringRefParams("hi", None) + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert result[1] == "output string" + + +def test_value_out_params(): + """Test use of value type out-parameters.""" + result = MethodTest.TestValueOutParams("hi", 1) + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert result[1] == 42 + + # None cannot be converted to a value type like int, long, etc. + with pytest.raises(TypeError): + MethodTest.TestValueOutParams("hi", None) + + +def test_value_ref_params(): + """Test use of value type byref parameters.""" + result = MethodTest.TestValueRefParams("hi", 1) + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert result[1] == 42 + + # None cannot be converted to a value type like int, long, etc. + with pytest.raises(TypeError): + MethodTest.TestValueRefParams("hi", None) + + +def test_object_out_params(): + """Test use of object out-parameters.""" + result = MethodTest.TestObjectOutParams("hi", MethodTest()) + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert isinstance(result[1], System.Exception) + + result = MethodTest.TestObjectOutParams("hi", None) + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert isinstance(result[1], System.Exception) + + +def test_object_ref_params(): + """Test use of object byref parameters.""" + result = MethodTest.TestObjectRefParams("hi", MethodTest()) + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert isinstance(result[1], System.Exception) + + result = MethodTest.TestObjectRefParams("hi", None) + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert isinstance(result[1], System.Exception) + + +def test_struct_out_params(): + """Test use of struct out-parameters.""" + result = MethodTest.TestStructOutParams("hi", System.Guid.NewGuid()) + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert isinstance(result[1], System.Guid) + + # None cannot be converted to a value type like a struct + with pytest.raises(TypeError): + MethodTest.TestValueRefParams("hi", None) + + +def test_struct_ref_params(): + """Test use of struct byref parameters.""" + result = MethodTest.TestStructRefParams("hi", System.Guid.NewGuid()) + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert isinstance(result[1], System.Guid) + + # None cannot be converted to a value type like a struct + with pytest.raises(TypeError): + MethodTest.TestValueRefParams("hi", None) + + +def test_void_single_out_param(): + """Test void method with single out-parameter.""" + result = MethodTest.TestVoidSingleOutParam(9) + assert result == 42 + + # None cannot be converted to a value type + with pytest.raises(TypeError): + MethodTest.TestVoidSingleOutParam(None) + + +def test_void_single_ref_param(): + """Test void method with single ref-parameter.""" + result = MethodTest.TestVoidSingleRefParam(9) + assert result == 42 + + # None cannot be converted to a value type + with pytest.raises(TypeError): + MethodTest.TestVoidSingleRefParam(None) + + +def test_single_default_param(): + """Test void method with single ref-parameter.""" + result = MethodTest.TestSingleDefaultParam() + assert result == 5 + + +def test_one_arg_and_two_default_param(): + """Test void method with single ref-parameter.""" + result = MethodTest.TestOneArgAndTwoDefaultParam(11) + assert result == 22 + + result = MethodTest.TestOneArgAndTwoDefaultParam(15) + assert result == 26 + + result = MethodTest.TestOneArgAndTwoDefaultParam(20) + assert result == 31 + + +def test_two_default_param(): + """Test void method with single ref-parameter.""" + result = MethodTest.TestTwoDefaultParam() + assert result == 11 + + +def test_explicit_selection_with_out_modifier(): + """Check explicit overload selection with out modifiers.""" + refstr = System.String("").GetType().MakeByRefType() + result = MethodTest.TestStringOutParams.__overloads__[str, refstr]( + "hi", "there") + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert result[1] == "output string" + + result = MethodTest.TestStringOutParams.__overloads__[str, refstr]( + "hi", None) + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert result[1] == "output string" + + +def test_explicit_selection_with_ref_modifier(): + """Check explicit overload selection with ref modifiers.""" + refstr = System.String("").GetType().MakeByRefType() + result = MethodTest.TestStringRefParams.__overloads__[str, refstr]( + "hi", "there") + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert result[1] == "output string" + + result = MethodTest.TestStringRefParams.__overloads__[str, refstr]( + "hi", None) + assert isinstance(result, tuple) + assert len(result) == 2 + assert result[0] is True + assert result[1] == "output string" + + +def test_explicit_overload_selection(): + """Check explicit overload selection using [] syntax.""" + from Python.Test import ISayHello1, InterfaceTest, ShortEnum + from System import Array + + inst = InterfaceTest() + + value = MethodTest.Overloaded.__overloads__[System.Boolean](True) + assert value is True + + value = MethodTest.Overloaded.__overloads__[bool](True) + assert value is True + + value = MethodTest.Overloaded.__overloads__[System.Byte](255) + assert value == 255 + + value = MethodTest.Overloaded.__overloads__[System.SByte](127) + assert value == 127 + + value = MethodTest.Overloaded.__overloads__[System.Char](u'A') + assert value == u'A' + + value = MethodTest.Overloaded.__overloads__[System.Char](65535) + assert value == unichr(65535) + + value = MethodTest.Overloaded.__overloads__[System.Int16](32767) + assert value == 32767 + + value = MethodTest.Overloaded.__overloads__[System.Int32](2147483647) + assert value == 2147483647 + + value = MethodTest.Overloaded.__overloads__[int](2147483647) + assert value == 2147483647 + + value = MethodTest.Overloaded.__overloads__[System.Int64]( + long(9223372036854775807)) + assert value == long(9223372036854775807) + + # Python 3 has no explicit long type, use System.Int64 instead + if PY2: + value = MethodTest.Overloaded.__overloads__[long]( + long(9223372036854775807)) + assert value == long(9223372036854775807) + + value = MethodTest.Overloaded.__overloads__[System.UInt16](65000) + assert value == 65000 + + value = MethodTest.Overloaded.__overloads__[System.UInt32]( + long(4294967295)) + assert value == long(4294967295) + + value = MethodTest.Overloaded.__overloads__[System.UInt64]( + long(18446744073709551615)) + assert value == long(18446744073709551615) + + value = MethodTest.Overloaded.__overloads__[System.Single](3.402823e38) + assert value == 3.402823e38 + + value = MethodTest.Overloaded.__overloads__[System.Double]( + 1.7976931348623157e308) + assert value == 1.7976931348623157e308 + + value = MethodTest.Overloaded.__overloads__[float]( + 1.7976931348623157e308) + assert value == 1.7976931348623157e308 + + value = MethodTest.Overloaded.__overloads__[System.Decimal]( + System.Decimal.One) + assert value == System.Decimal.One + + value = MethodTest.Overloaded.__overloads__[System.String]("spam") + assert value == "spam" + + value = MethodTest.Overloaded.__overloads__[str]("spam") + assert value == "spam" + + value = MethodTest.Overloaded.__overloads__[ShortEnum](ShortEnum.Zero) + assert value == ShortEnum.Zero + + value = MethodTest.Overloaded.__overloads__[System.Object](inst) + assert value.__class__ == inst.__class__ + + value = MethodTest.Overloaded.__overloads__[InterfaceTest](inst) + assert value.__class__ == inst.__class__ + + value = MethodTest.Overloaded.__overloads__[ISayHello1](inst) + assert value.__class__ == inst.__class__ + + atype = Array[System.Object] + value = MethodTest.Overloaded.__overloads__[str, int, atype]( + "one", 1, atype([1, 2, 3])) + assert value == 3 + + value = MethodTest.Overloaded.__overloads__[str, int]("one", 1) + assert value == 1 + + value = MethodTest.Overloaded.__overloads__[int, str](1, "one") + assert value == 1 + + +def test_overload_selection_with_array_types(): + """Check overload selection using array types.""" + from Python.Test import ISayHello1, InterfaceTest, ShortEnum + from System import Array + + inst = InterfaceTest() + + vtype = Array[System.Boolean] + input_ = vtype([True, True]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] is True + assert value[1] is True + + vtype = Array[bool] + input_ = vtype([True, True]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] is True + assert value[1] is True + + vtype = Array[System.Byte] + input_ = vtype([0, 255]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == 0 + assert value[1] == 255 + + vtype = Array[System.SByte] + input_ = vtype([0, 127]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == 0 + assert value[1] == 127 + + vtype = Array[System.Char] + input_ = vtype([u'A', u'Z']) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == u'A' + assert value[1] == u'Z' + + vtype = Array[System.Char] + input_ = vtype([0, 65535]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == unichr(0) + assert value[1] == unichr(65535) + + vtype = Array[System.Int16] + input_ = vtype([0, 32767]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == 0 + assert value[1] == 32767 + + vtype = Array[System.Int32] + input_ = vtype([0, 2147483647]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == 0 + assert value[1] == 2147483647 + + vtype = Array[int] + input_ = vtype([0, 2147483647]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == 0 + assert value[1] == 2147483647 + + vtype = Array[System.Int64] + input_ = vtype([0, long(9223372036854775807)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == 0 + assert value[1] == long(9223372036854775807) + + # Python 3 has no explicit long type, use System.Int64 instead + if PY2: + vtype = Array[long] + input_ = vtype([0, long(9223372036854775807)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == 0 + assert value[1] == long(9223372036854775807) + + vtype = Array[System.UInt16] + input_ = vtype([0, 65000]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == 0 + assert value[1] == 65000 + + vtype = Array[System.UInt32] + input_ = vtype([0, long(4294967295)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == 0 + assert value[1] == long(4294967295) + + vtype = Array[System.UInt64] + input_ = vtype([0, long(18446744073709551615)]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == 0 + assert value[1] == long(18446744073709551615) + + vtype = Array[System.Single] + input_ = vtype([0.0, 3.402823e38]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == 0.0 + assert value[1] == 3.402823e38 + + vtype = Array[System.Double] + input_ = vtype([0.0, 1.7976931348623157e308]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == 0.0 + assert value[1] == 1.7976931348623157e308 + + vtype = Array[float] + input_ = vtype([0.0, 1.7976931348623157e308]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == 0.0 + assert value[1] == 1.7976931348623157e308 + + vtype = Array[System.Decimal] + input_ = vtype([System.Decimal.Zero, System.Decimal.One]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == System.Decimal.Zero + assert value[1] == System.Decimal.One + + vtype = Array[System.String] + input_ = vtype(["one", "two"]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == "one" + assert value[1] == "two" + + vtype = Array[str] + input_ = vtype(["one", "two"]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == "one" + assert value[1] == "two" + + vtype = Array[ShortEnum] + input_ = vtype([ShortEnum.Zero, ShortEnum.One]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0] == ShortEnum.Zero + assert value[1] == ShortEnum.One + + vtype = Array[System.Object] + input_ = vtype([inst, inst]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].__class__ == inst.__class__ + assert value[1].__class__ == inst.__class__ + + vtype = Array[InterfaceTest] + input_ = vtype([inst, inst]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].__class__ == inst.__class__ + assert value[1].__class__ == inst.__class__ + + vtype = Array[ISayHello1] + input_ = vtype([inst, inst]) + value = MethodTest.Overloaded.__overloads__[vtype](input_) + assert value[0].__class__ == inst.__class__ + assert value[1].__class__ == inst.__class__ + + +def test_explicit_overload_selection_failure(): + """Check that overload selection fails correctly.""" + + with pytest.raises(TypeError): + _ = MethodTest.Overloaded.__overloads__[System.Type](True) + + with pytest.raises(TypeError): + _ = MethodTest.Overloaded.__overloads__[int, int](1, 1) + + with pytest.raises(TypeError): + _ = MethodTest.Overloaded.__overloads__[str, int, int]("", 1, 1) + + with pytest.raises(TypeError): + _ = MethodTest.Overloaded.__overloads__[int, long](1) + + +def test_we_can_bind_to_encoding_get_string(): + """Check that we can bind to the Encoding.GetString method + with variables.""" + from System.Text import Encoding + from System.IO import MemoryStream + + my_bytes = Encoding.UTF8.GetBytes('Some testing string') + stream = MemoryStream() + stream.Write(my_bytes, 0, my_bytes.Length) + stream.Position = 0 + + buff = System.Array.CreateInstance(System.Byte, 3) + buff.Initialize() + data = [] + read = 1 + + while read > 0: + read, _ = stream.Read(buff, 0, buff.Length) + temp = Encoding.UTF8.GetString(buff, 0, read) + data.append(temp) + + data = ''.join(data) + assert data == 'Some testing string' + + +def test_wrong_overload(): + """Test regression in which implicit conversion caused the wrong types + to be used. See #131 for issue. Fixed by #137, #151""" + + # Used to return `50L` + res = System.Math.Abs(50.5) + assert res == 50.5 + assert type(res) == float + + res = System.Math.Abs(-50.5) + assert res == 50.5 + assert type(res) == float + + res = System.Math.Max(50.5, 50.1) + assert res == 50.5 + assert type(res) == float + + res = System.Math.Max(System.Double(10.5), System.Double(50.5)) + assert res == 50.5 + assert type(res) == float # Should it return a System.Double? + + res = System.Math.Max(System.Double(50.5), 50.1) + assert res == 50.5 + assert type(res) == float + + +def test_no_object_in_param(): + """Test that fix for #203 doesn't break behavior w/ no object overload""" + + res = MethodTest.TestOverloadedNoObject(5) + assert res == "Got int" + + with pytest.raises(TypeError): + MethodTest.TestOverloadedNoObject("test") + + +def test_object_in_param(): + """Test regression introduced by #151 in which Object method overloads + aren't being used. See #203 for issue.""" + + res = MethodTest.TestOverloadedObject(5) + assert res == "Got int" + + res = MethodTest.TestOverloadedObject("test") + assert res == "Got object" + + +def test_object_in_multiparam(): + """Test method with object multiparams behaves""" + + res = MethodTest.TestOverloadedObjectTwo(5, 5) + assert res == "Got int-int" + + res = MethodTest.TestOverloadedObjectTwo(5, "foo") + assert res == "Got int-string" + + res = MethodTest.TestOverloadedObjectTwo("foo", 7.24) + assert res == "Got string-object" + + res = MethodTest.TestOverloadedObjectTwo("foo", "bar") + assert res == "Got string-string" + + res = MethodTest.TestOverloadedObjectTwo("foo", 5) + assert res == "Got string-int" + + res = MethodTest.TestOverloadedObjectTwo(7.24, 7.24) + assert res == "Got object-object" + + +def test_object_in_multiparam_exception(): + """Test method with object multiparams behaves""" + + with pytest.raises(TypeError): + MethodTest.TestOverloadedObjectThree("foo", "bar") + + +def test_case_sensitive(): + """Test that case-sensitivity is respected. GH#81""" + + res = MethodTest.CaseSensitive() + assert res == "CaseSensitive" + + res = MethodTest.Casesensitive() + assert res == "Casesensitive" + + with pytest.raises(AttributeError): + MethodTest.casesensitive() diff --git a/src/tests/test_module.py b/src/tests/test_module.py index fff044f0c..62d79b9ab 100644 --- a/src/tests/test_module.py +++ b/src/tests/test_module.py @@ -1,389 +1,395 @@ -import clr +# -*- coding: utf-8 -*- -clr.AddReference('Python.Test') -clr.AddReference('System.Data') +"""Test CLR modules and the CLR import hook.""" -# testImplicitAssemblyLoad() passes on deprecation warning; perfect! # -##clr.AddReference('System.Windows.Forms') -import sys, os, string, unittest, types, warnings +import clr +import time +import types +import warnings from fnmatch import fnmatch -import six -if six.PY3: - ClassType = type -else: - ClassType = types.ClassType +import pytest +from ._compat import ClassType, PY2, PY3, range +from .utils import is_clr_class, is_clr_module, is_clr_root_module -class ModuleTests(unittest.TestCase): - """Test CLR modules and the CLR import hook.""" - def isCLRModule(self, object): - return type(object).__name__ == 'ModuleObject' +# testImplicitAssemblyLoad() passes on deprecation warning; perfect! # +# clr.AddReference('System.Windows.Forms') + +def test_import_hook_works(): + """Test that the import hook works correctly both using the + included runtime and an external runtime. This must be + the first test run in the unit tests!""" + from System import String + + +def test_import_clr(): + import clr + assert is_clr_root_module(clr) + + +def test_version_clr(): + import clr + assert clr.__version__ >= "2.2.0" + + +def test_preload_var(): + import clr + assert clr.getPreload() is False, clr.getPreload() + clr.setPreload(False) + assert clr.getPreload() is False, clr.getPreload() + try: + clr.setPreload(True) + assert clr.getPreload() is True, clr.getPreload() + clr.setPreload(0) + assert clr.getPreload() is False, clr.getPreload() + clr.setPreload(1) + assert clr.getPreload() is True, clr.getPreload() + + import System.Configuration + content = dir(System.Configuration) + assert len(content) > 10, content + finally: + clr.setPreload(False) - def isCLRRootModule(self, object): - if six.PY3: - # in Python 3 the clr module is a normal python module - return object.__name__ == "clr" - return type(object).__name__ == 'CLRModule' - def isCLRClass(self, object): - return type(object).__name__ == 'CLR Metatype' # for now +def test_module_interface(): + """Test the interface exposed by CLR module objects.""" + import System + assert type(System.__dict__) == type({}) + assert System.__name__ == 'System' + # the filename can be any module from the System namespace + # (eg System.Data.dll or System.dll, but also mscorlib.dll) + system_file = System.__file__ + assert fnmatch(system_file, "*System*.dll") or fnmatch(system_file, "*mscorlib.dll"), \ + "unexpected System.__file__: " + system_file + assert System.__doc__.startswith("Namespace containing types from the following assemblies:") + assert is_clr_class(System.String) + assert is_clr_class(System.Int32) + + +def test_simple_import(): + """Test simple import.""" + import System + assert is_clr_module(System) + assert System.__name__ == 'System' + + import sys + assert isinstance(sys, types.ModuleType) + assert sys.__name__ == 'sys' + + if PY3: + import http.client as httplib + assert isinstance(httplib, types.ModuleType) + assert httplib.__name__ == 'http.client' + elif PY2: + import httplib + assert isinstance(httplib, types.ModuleType) + assert httplib.__name__ == 'httplib' + + +def test_simple_import_with_alias(): + """Test simple import with aliasing.""" + import System as mySystem + assert is_clr_module(mySystem) + assert mySystem.__name__ == 'System' + + import sys as mySys + assert isinstance(mySys, types.ModuleType) + assert mySys.__name__ == 'sys' + + if PY3: + import http.client as myHttplib + assert isinstance(myHttplib, types.ModuleType) + assert myHttplib.__name__ == 'http.client' + elif PY2: + import httplib as myHttplib + assert isinstance(myHttplib, types.ModuleType) + assert myHttplib.__name__ == 'httplib' + + +def test_dotted_name_import(): + """Test dotted-name import.""" + import System.Reflection + assert is_clr_module(System.Reflection) + assert System.Reflection.__name__ == 'System.Reflection' + + import xml.dom + assert isinstance(xml.dom, types.ModuleType) + assert xml.dom.__name__ == 'xml.dom' + + +def test_multiple_dotted_name_import(): + """Test an import bug with multiple dotted imports.""" + import System.Data + assert is_clr_module(System.Data) + assert System.Data.__name__ == 'System.Data' + import System.Data + assert is_clr_module(System.Data) + assert System.Data.__name__ == 'System.Data' + + +def test_dotted_name_import_with_alias(): + """Test dotted-name import with aliasing.""" + import System.Reflection as SysRef + assert is_clr_module(SysRef) + assert SysRef.__name__ == 'System.Reflection' + + import xml.dom as myDom + assert isinstance(myDom, types.ModuleType) + assert myDom.__name__ == 'xml.dom' + + +def test_simple_import_from(): + """Test simple 'import from'.""" + from System import Reflection + assert is_clr_module(Reflection) + assert Reflection.__name__ == 'System.Reflection' + + from xml import dom + assert isinstance(dom, types.ModuleType) + assert dom.__name__ == 'xml.dom' + + +def test_simple_import_from_with_alias(): + """Test simple 'import from' with aliasing.""" + from System import Collections as Coll + assert is_clr_module(Coll) + assert Coll.__name__ == 'System.Collections' + + from xml import dom as myDom + assert isinstance(myDom, types.ModuleType) + assert myDom.__name__ == 'xml.dom' + + +def test_dotted_name_import_from(): + """Test dotted-name 'import from'.""" + from System.Collections import Specialized + assert is_clr_module(Specialized) + assert Specialized.__name__ == 'System.Collections.Specialized' + + from System.Collections.Specialized import StringCollection + assert is_clr_class(StringCollection) + assert StringCollection.__name__ == 'StringCollection' - def testAAAImportHookWorks(self): - """Test that the import hook works correctly both using the - included runtime and an external runtime. This must be - the first test run in the unit tests!""" + from xml.dom import pulldom + assert isinstance(pulldom, types.ModuleType) + assert pulldom.__name__ == 'xml.dom.pulldom' - from System import String + from xml.dom.pulldom import PullDOM + assert isinstance(PullDOM, ClassType) + assert PullDOM.__name__ == 'PullDOM' - def test000importClr(self): - import clr - self.assertTrue(self.isCLRRootModule(clr)) - def testVersionClr(self): - import clr - self.assertTrue(clr.__version__ >= "2.2.0") +def test_dotted_name_import_from_with_alias(): + """Test dotted-name 'import from' with aliasing.""" + from System.Collections import Specialized as Spec + assert is_clr_module(Spec) + assert Spec.__name__ == 'System.Collections.Specialized' - def testPreloadVar(self): - import clr - self.assertTrue(clr.getPreload() is False, clr.getPreload()) - clr.setPreload(False) - self.assertTrue(clr.getPreload() is False, clr.getPreload()) - try: - clr.setPreload(True) - self.assertTrue(clr.getPreload() is True, clr.getPreload()) - clr.setPreload(0) - self.assertTrue(clr.getPreload() is False, clr.getPreload()) - clr.setPreload(1) - self.assertTrue(clr.getPreload() is True, clr.getPreload()) - - import System.Configuration - content = dir(System.Configuration) - self.assertTrue(len(content) > 10, content) - finally: - clr.setPreload(False) - - def testModuleInterface(self): - """Test the interface exposed by CLR module objects.""" - import System - self.assertEquals(type(System.__dict__), type({})) - self.assertEquals(System.__name__, 'System') - # the filename can be any module from the System namespace - # (eg System.Data.dll or System.dll, but also mscorlib.dll) - system_file = System.__file__ - self.assertTrue(fnmatch(system_file, "*System*.dll") or fnmatch(system_file, "*mscorlib.dll"), - "unexpected System.__file__: " + system_file) - self.assertTrue(System.__doc__.startswith("Namespace containing types from the following assemblies:")) - self.assertTrue(self.isCLRClass(System.String)) - self.assertTrue(self.isCLRClass(System.Int32)) - - def testSimpleImport(self): - """Test simple import.""" - import System - self.assertTrue(self.isCLRModule(System)) - self.assertTrue(System.__name__ == 'System') - - import sys - self.assertTrue(type(sys) == types.ModuleType) - self.assertTrue(sys.__name__ == 'sys') - - if six.PY3: - import http.client as httplib - self.assertTrue(type(httplib) == types.ModuleType) - self.assertTrue(httplib.__name__ == 'http.client') - else: - import httplib - self.assertTrue(type(httplib) == types.ModuleType) - self.assertTrue(httplib.__name__ == 'httplib') - - def testSimpleImportWithAlias(self): - """Test simple import with aliasing.""" - import System as mySystem - self.assertTrue(self.isCLRModule(mySystem)) - self.assertTrue(mySystem.__name__ == 'System') - - import sys as mySys - self.assertTrue(type(mySys) == types.ModuleType) - self.assertTrue(mySys.__name__ == 'sys') - - if six.PY3: - import http.client as myHttplib - self.assertTrue(type(myHttplib) == types.ModuleType) - self.assertTrue(myHttplib.__name__ == 'http.client') - else: - import httplib as myHttplib - self.assertTrue(type(myHttplib) == types.ModuleType) - self.assertTrue(myHttplib.__name__ == 'httplib') - - def testDottedNameImport(self): - """Test dotted-name import.""" - import System.Reflection - self.assertTrue(self.isCLRModule(System.Reflection)) - self.assertTrue(System.Reflection.__name__ == 'System.Reflection') - - import xml.dom - self.assertTrue(type(xml.dom) == types.ModuleType) - self.assertTrue(xml.dom.__name__ == 'xml.dom') - - def testMultipleDottedNameImport(self): - """Test an import bug with multiple dotted imports.""" - import System.Data - self.assertTrue(self.isCLRModule(System.Data)) - self.assertTrue(System.Data.__name__ == 'System.Data') - import System.Data - self.assertTrue(self.isCLRModule(System.Data)) - self.assertTrue(System.Data.__name__ == 'System.Data') - - def testDottedNameImportWithAlias(self): - """Test dotted-name import with aliasing.""" - import System.Reflection as SysRef - self.assertTrue(self.isCLRModule(SysRef)) - self.assertTrue(SysRef.__name__ == 'System.Reflection') - - import xml.dom as myDom - self.assertTrue(type(myDom) == types.ModuleType) - self.assertTrue(myDom.__name__ == 'xml.dom') - - def testSimpleImportFrom(self): - """Test simple 'import from'.""" - from System import Reflection - self.assertTrue(self.isCLRModule(Reflection)) - self.assertTrue(Reflection.__name__ == 'System.Reflection') - - from xml import dom - self.assertTrue(type(dom) == types.ModuleType) - self.assertTrue(dom.__name__ == 'xml.dom') - - def testSimpleImportFromWithAlias(self): - """Test simple 'import from' with aliasing.""" - from System import Collections as Coll - self.assertTrue(self.isCLRModule(Coll)) - self.assertTrue(Coll.__name__ == 'System.Collections') - - from xml import dom as myDom - self.assertTrue(type(myDom) == types.ModuleType) - self.assertTrue(myDom.__name__ == 'xml.dom') - - def testDottedNameImportFrom(self): - """Test dotted-name 'import from'.""" - from System.Collections import Specialized - self.assertTrue(self.isCLRModule(Specialized)) - self.assertTrue( - Specialized.__name__ == 'System.Collections.Specialized' - ) - - from System.Collections.Specialized import StringCollection - self.assertTrue(self.isCLRClass(StringCollection)) - self.assertTrue(StringCollection.__name__ == 'StringCollection') - - from xml.dom import pulldom - self.assertTrue(type(pulldom) == types.ModuleType) - self.assertTrue(pulldom.__name__ == 'xml.dom.pulldom') - - from xml.dom.pulldom import PullDOM - self.assertTrue(type(PullDOM) == ClassType) - self.assertTrue(PullDOM.__name__ == 'PullDOM') - - def testDottedNameImportFromWithAlias(self): - """Test dotted-name 'import from' with aliasing.""" - from System.Collections import Specialized as Spec - self.assertTrue(self.isCLRModule(Spec)) - self.assertTrue(Spec.__name__ == 'System.Collections.Specialized') - - from System.Collections.Specialized import StringCollection as SC - self.assertTrue(self.isCLRClass(SC)) - self.assertTrue(SC.__name__ == 'StringCollection') - - from xml.dom import pulldom as myPulldom - self.assertTrue(type(myPulldom) == types.ModuleType) - self.assertTrue(myPulldom.__name__ == 'xml.dom.pulldom') - - from xml.dom.pulldom import PullDOM as myPullDOM - self.assertTrue(type(myPullDOM) == ClassType) - self.assertTrue(myPullDOM.__name__ == 'PullDOM') - - def testFromModuleImportStar(self): - """Test from module import * behavior.""" - count = len(locals().keys()) - m = __import__('System.Xml', globals(), locals(), ['*']) - self.assertTrue(m.__name__ == 'System.Xml') - self.assertTrue(self.isCLRModule(m)) - self.assertTrue(len(locals().keys()) > count + 1) - - def testImplicitAssemblyLoad(self): - """Test implicit assembly loading via import.""" - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - - # should trigger a DeprecationWarning as Microsoft.Build hasn't - # been added as a reference yet (and should exist for mono) - import Microsoft.Build - - self.assertEqual(len(w), 1) - self.assertTrue(isinstance(w[0].message, DeprecationWarning)) - - with warnings.catch_warnings(record=True) as w: - clr.AddReference("System.Windows.Forms") - import System.Windows.Forms as Forms - self.assertTrue(self.isCLRModule(Forms)) - self.assertTrue(Forms.__name__ == 'System.Windows.Forms') - from System.Windows.Forms import Form - self.assertTrue(self.isCLRClass(Form)) - self.assertTrue(Form.__name__ == 'Form') - self.assertEqual(len(w), 0) - - def testExplicitAssemblyLoad(self): - """Test explicit assembly loading using standard CLR tools.""" - from System.Reflection import Assembly - import System, sys - - assembly = Assembly.LoadWithPartialName('System.Data') - self.assertTrue(assembly != None) - - import System.Data - self.assertTrue('System.Data' in sys.modules) - - assembly = Assembly.LoadWithPartialName('SpamSpamSpamSpamEggsAndSpam') - self.assertTrue(assembly == None) - - def testImplicitLoadAlreadyValidNamespace(self): - """Test implicit assembly load over an already valid namespace.""" - # In this case, the mscorlib assembly (loaded by default) defines - # a number of types in the System namespace. There is also a System - # assembly, which is _not_ loaded by default, which also contains - # types in the System namespace. The desired behavior is for the - # Python runtime to "do the right thing", allowing types from both - # assemblies to be found in the System module implicitly. - import System - self.assertTrue(self.isCLRClass(System.UriBuilder)) - - def testImportNonExistantModule(self): - """Test import failure for a non-existant module.""" - - def test(): - import System.SpamSpamSpam + from System.Collections.Specialized import StringCollection as SC + assert is_clr_class(SC) + assert SC.__name__ == 'StringCollection' - self.assertTrue(ImportError, test) - - def testLookupNoNamespaceType(self): - """Test lookup of types without a qualified namespace.""" - import Python.Test - import clr - self.assertTrue(self.isCLRClass(clr.NoNamespaceType)) + from xml.dom import pulldom as myPulldom + assert isinstance(myPulldom, types.ModuleType) + assert myPulldom.__name__ == 'xml.dom.pulldom' - def testModuleLookupRecursion(self): - """Test for recursive lookup handling.""" + from xml.dom.pulldom import PullDOM as myPullDOM + assert isinstance(myPullDOM, ClassType) + assert myPullDOM.__name__ == 'PullDOM' - def test1(): - from System import System - self.assertTrue(ImportError, test1) +def test_from_module_import_star(): + """Test from module import * behavior.""" + count = len(locals().keys()) + m = __import__('System.Xml', globals(), locals(), ['*']) + assert m.__name__ == 'System.Xml' + assert is_clr_module(m) + assert len(locals().keys()) > count + 1 - def test2(): - import System - x = System.System - self.assertTrue(AttributeError, test2) +def test_implicit_assembly_load(): + """Test implicit assembly loading via import.""" + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") - def testModuleGetAttr(self): - """Test module getattr behavior.""" - import System + # should trigger a DeprecationWarning as Microsoft.Build hasn't + # been added as a reference yet (and should exist for mono) + import Microsoft.Build - int_type = System.Int32 - self.assertTrue(self.isCLRClass(int_type)) + assert len(w) == 1 + assert isinstance(w[0].message, DeprecationWarning) - module = System.Xml - self.assertTrue(self.isCLRModule(module)) + with warnings.catch_warnings(record=True) as w: + clr.AddReference("System.Windows.Forms") + import System.Windows.Forms as Forms + assert is_clr_module(Forms) + assert Forms.__name__ == 'System.Windows.Forms' + from System.Windows.Forms import Form + assert is_clr_class(Form) + assert Form.__name__ == 'Form' + assert len(w) == 0 - def test(): - spam = System.Spam - self.assertTrue(AttributeError, test) +def test_explicit_assembly_load(): + """Test explicit assembly loading using standard CLR tools.""" + from System.Reflection import Assembly + import System, sys - def test(): - spam = getattr(System, 1) + assembly = Assembly.LoadWithPartialName('System.Data') + assert assembly is not None - self.assertTrue(TypeError, test) + import System.Data + assert 'System.Data' in sys.modules - def testModuleAttrAbuse(self): - """Test handling of attempts to set module attributes.""" + assembly = Assembly.LoadWithPartialName('SpamSpamSpamSpamEggsAndSpam') + assert assembly is None - # It would be safer to use a dict-proxy as the __dict__ for CLR - # modules, but as of Python 2.3 some parts of the CPython runtime - # like dir() will fail if a module dict is not a real dictionary. - def test(): - import System - System.__dict__['foo'] = 0 - return 1 +def test_implicit_load_already_valid_namespace(): + """Test implicit assembly load over an already valid namespace.""" + # In this case, the mscorlib assembly (loaded by default) defines + # a number of types in the System namespace. There is also a System + # assembly, which is _not_ loaded by default, which also contains + # types in the System namespace. The desired behavior is for the + # Python runtime to "do the right thing", allowing types from both + # assemblies to be found in the System module implicitly. + import System + assert is_clr_class(System.UriBuilder) - self.assertTrue(test()) - def testModuleTypeAbuse(self): - """Test handling of attempts to break the module type.""" - import System - mtype = type(System) +def test_import_non_existant_module(): + """Test import failure for a non-existent module.""" + with pytest.raises(ImportError): + import System.SpamSpamSpam - def test(): - mtype.__getattribute__(0, 'spam') - self.assertTrue(TypeError, test) +def test_lookup_no_namespace_type(): + """Test lookup of types without a qualified namespace.""" + import Python.Test + import clr + assert is_clr_class(clr.NoNamespaceType) - def test(): - mtype.__setattr__(0, 'spam', 1) - self.assertTrue(TypeError, test) +def test_module_lookup_recursion(): + """Test for recursive lookup handling.""" - def test(): - mtype.__repr__(0) + with pytest.raises(ImportError): + from System import System - self.assertTrue(TypeError, test) + with pytest.raises(AttributeError): + import System + _ = System.System - def test_ClrListAssemblies(self): - from clr import ListAssemblies - verbose = list(ListAssemblies(True)) - short = list(ListAssemblies(False)) - self.assertTrue(six.u('mscorlib') in short) - self.assertTrue(six.u('System') in short) - self.assertTrue(six.u('Culture=') in verbose[0]) - self.assertTrue(six.u('Version=') in verbose[0]) - def test_ClrAddReference(self): - from clr import AddReference - from System.IO import FileNotFoundException - for name in ("System", "Python.Runtime"): - assy = AddReference(name) - assyName = assy.GetName().Name - self.assertEqual(assyName, name) +def test_module_get_attr(): + """Test module getattr behavior.""" + import System - self.assertRaises(FileNotFoundException, - AddReference, "somethingtotallysilly") + int_type = System.Int32 + assert is_clr_class(int_type) - def test_AssemblyLoadThreadSafety(self): - import time - from Python.Test import ModuleTest - # spin up .NET thread which loads assemblies and triggers AppDomain.AssemblyLoad event - ModuleTest.RunThreads() - time.sleep(1e-5) - for i in range(1, 100): - # call import clr, which in AssemblyManager.GetNames iterates through the loaded types - import clr - # import some .NET types - from System import DateTime - from System import Guid - from System.Collections.Generic import Dictionary - dict = Dictionary[Guid,DateTime]() - ModuleTest.JoinThreads() + module = System.Xml + assert is_clr_module(module) + with pytest.raises(AttributeError): + _ = System.Spam -def test_suite(): - return unittest.makeSuite(ModuleTests) + with pytest.raises(TypeError): + _ = getattr(System, 1) -def main(): - unittest.TextTestRunner().run(test_suite()) +def test_module_attr_abuse(): + """Test handling of attempts to set module attributes.""" + # It would be safer to use a dict-proxy as the __dict__ for CLR + # modules, but as of Python 2.3 some parts of the CPython runtime + # like dir() will fail if a module dict is not a real dictionary. -if __name__ == '__main__': - main() + def test(): + import System + System.__dict__['foo'] = 0 + return 1 + + assert test() + + +def test_module_type_abuse(): + """Test handling of attempts to break the module type.""" + import System + mtype = type(System) + + with pytest.raises(TypeError): + mtype.__getattribute__(0, 'spam') + + with pytest.raises(TypeError): + mtype.__setattr__(0, 'spam', 1) + + with pytest.raises(TypeError): + mtype.__repr__(0) + + +def test_clr_list_assemblies(): + from clr import ListAssemblies + verbose = list(ListAssemblies(True)) + short = list(ListAssemblies(False)) + assert u'mscorlib' in short + assert u'System' in short + assert u'Culture=' in verbose[0] + assert u'Version=' in verbose[0] + + +def test_clr_add_reference(): + from clr import AddReference + from System.IO import FileNotFoundException + for name in ("System", "Python.Runtime"): + assy = AddReference(name) + assy_name = assy.GetName().Name + assert assy_name == name + + with pytest.raises(FileNotFoundException): + AddReference("somethingtotallysilly") + +def test_clr_get_clr_type(): + """Test clr.GetClrType().""" + from clr import GetClrType + import System + from System import IComparable + from System import ArgumentException + assert GetClrType(System.String).FullName == "System.String" + comparable = GetClrType(IComparable) + assert comparable.FullName == "System.IComparable" + assert comparable.IsInterface + assert GetClrType(int).FullName == "System.Int32" + assert GetClrType(str).FullName == "System.String" + assert GetClrType(float).FullName == "System.Double" + dblarr = System.Array[System.Double] + assert GetClrType(dblarr).FullName == "System.Double[]" + + with pytest.raises(TypeError): + GetClrType(1) + with pytest.raises(TypeError): + GetClrType("thiswillfail") + +def test_assembly_load_thread_safety(): + from Python.Test import ModuleTest + # spin up .NET thread which loads assemblies and triggers AppDomain.AssemblyLoad event + ModuleTest.RunThreads() + time.sleep(1e-5) + for _ in range(1, 100): + # call import clr, which in AssemblyManager.GetNames iterates through the loaded types + import clr + # import some .NET types + from System import DateTime + from System import Guid + from System.Collections.Generic import Dictionary + _ = Dictionary[Guid, DateTime]() + ModuleTest.JoinThreads() + +def test_assembly_load_recursion_bug(): + """Test fix for recursion bug documented in #627""" + from System.Configuration import ConfigurationManager + content = dir(ConfigurationManager) + assert len(content) > 5, content diff --git a/src/tests/test_property.py b/src/tests/test_property.py index 5bb653848..4dc8ea111 100644 --- a/src/tests/test_property.py +++ b/src/tests/test_property.py @@ -1,186 +1,148 @@ -import sys, os, string, unittest, types -from Python.Test import PropertyTest -import six - -if six.PY3: - IntType = int -else: - IntType = types.IntType - - -class PropertyTests(unittest.TestCase): - """Test CLR property support.""" - - def testPublicInstanceProperty(self): - """Test public instance properties.""" - object = PropertyTest(); - - self.assertTrue(object.PublicProperty == 0) - object.PublicProperty = 1 - self.assertTrue(object.PublicProperty == 1) - - def test(): - del PropertyTest().PublicProperty +# -*- coding: utf-8 -*- - self.assertRaises(TypeError, test) +"""Test CLR property support.""" - def testPublicStaticProperty(self): - """Test public static properties.""" - object = PropertyTest(); - - self.assertTrue(PropertyTest.PublicStaticProperty == 0) - PropertyTest.PublicStaticProperty = 1 - self.assertTrue(PropertyTest.PublicStaticProperty == 1) - - self.assertTrue(object.PublicStaticProperty == 1) - object.PublicStaticProperty = 0 - self.assertTrue(object.PublicStaticProperty == 0) - - def test(): - del PropertyTest.PublicStaticProperty - - self.assertRaises(TypeError, test) - - def test(): - del PropertyTest().PublicStaticProperty - - self.assertRaises(TypeError, test) +import pytest +from Python.Test import PropertyTest - def testProtectedInstanceProperty(self): - """Test protected instance properties.""" - object = PropertyTest(); - self.assertTrue(object.ProtectedProperty == 0) - object.ProtectedProperty = 1 - self.assertTrue(object.ProtectedProperty == 1) +def test_public_instance_property(): + """Test public instance properties.""" + ob = PropertyTest() - def test(): - del PropertyTest().ProtectedProperty + assert ob.PublicProperty == 0 + ob.PublicProperty = 1 + assert ob.PublicProperty == 1 - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + del PropertyTest().PublicProperty - def testProtectedStaticProperty(self): - """Test protected static properties.""" - object = PropertyTest(); - self.assertTrue(PropertyTest.ProtectedStaticProperty == 0) - PropertyTest.ProtectedStaticProperty = 1 - self.assertTrue(PropertyTest.ProtectedStaticProperty == 1) +def test_public_static_property(): + """Test public static properties.""" + ob = PropertyTest() - self.assertTrue(object.ProtectedStaticProperty == 1) - object.ProtectedStaticProperty = 0 - self.assertTrue(object.ProtectedStaticProperty == 0) + assert PropertyTest.PublicStaticProperty == 0 + PropertyTest.PublicStaticProperty = 1 + assert PropertyTest.PublicStaticProperty == 1 - def test(): - del PropertyTest.ProtectedStaticProperty + assert ob.PublicStaticProperty == 1 + ob.PublicStaticProperty = 0 + assert ob.PublicStaticProperty == 0 - self.assertRaises(TypeError, test) + with pytest.raises(TypeError): + del PropertyTest.PublicStaticProperty - def test(): - del PropertyTest().ProtectedStaticProperty + with pytest.raises(TypeError): + del PropertyTest().PublicStaticProperty - self.assertRaises(TypeError, test) - def testInternalProperty(self): - """Test internal properties.""" +def test_protected_instance_property(): + """Test protected instance properties.""" + ob = PropertyTest() - def test(): - f = PropertyTest().InternalProperty + assert ob.ProtectedProperty == 0 + ob.ProtectedProperty = 1 + assert ob.ProtectedProperty == 1 - self.assertRaises(AttributeError, test) + with pytest.raises(TypeError): + del PropertyTest().ProtectedProperty - def test(): - f = PropertyTest().InternalStaticProperty - self.assertRaises(AttributeError, test) +def test_protected_static_property(): + """Test protected static properties.""" + ob = PropertyTest() - def test(): - f = PropertyTest.InternalStaticProperty + assert PropertyTest.ProtectedStaticProperty == 0 + PropertyTest.ProtectedStaticProperty = 1 + assert PropertyTest.ProtectedStaticProperty == 1 - self.assertRaises(AttributeError, test) + assert ob.ProtectedStaticProperty == 1 + ob.ProtectedStaticProperty = 0 + assert ob.ProtectedStaticProperty == 0 - def testPrivateProperty(self): - """Test private properties.""" + with pytest.raises(TypeError): + del PropertyTest.ProtectedStaticProperty - def test(): - f = PropertyTest().PrivateProperty + with pytest.raises(TypeError): + del PropertyTest().ProtectedStaticProperty - self.assertRaises(AttributeError, test) - def test(): - f = PropertyTest().PrivateStaticProperty +def test_internal_property(): + """Test internal properties.""" - self.assertRaises(AttributeError, test) + with pytest.raises(AttributeError): + _ = PropertyTest().InternalProperty - def test(): - f = PropertyTest.PrivateStaticProperty + with pytest.raises(AttributeError): + _ = PropertyTest().InternalStaticProperty - self.assertRaises(AttributeError, test) + with pytest.raises(AttributeError): + _ = PropertyTest.InternalStaticProperty - def testPropertyDescriptorGetSet(self): - """Test property descriptor get / set.""" - # This test ensures that setting an attribute implemented with - # a descriptor actually goes through the descriptor (rather than - # silently replacing the descriptor in the instance or type dict. +def test_private_property(): + """Test private properties.""" - object = PropertyTest() + with pytest.raises(AttributeError): + _ = PropertyTest().PrivateProperty - self.assertTrue(PropertyTest.PublicStaticProperty == 0) - self.assertTrue(object.PublicStaticProperty == 0) + with pytest.raises(AttributeError): + _ = PropertyTest().PrivateStaticProperty - descriptor = PropertyTest.__dict__['PublicStaticProperty'] - self.assertTrue(type(descriptor) != IntType) + with pytest.raises(AttributeError): + _ = PropertyTest.PrivateStaticProperty - object.PublicStaticProperty = 0 - descriptor = PropertyTest.__dict__['PublicStaticProperty'] - self.assertTrue(type(descriptor) != IntType) - PropertyTest.PublicStaticProperty = 0 - descriptor = PropertyTest.__dict__['PublicStaticProperty'] - self.assertTrue(type(descriptor) != IntType) +def test_property_descriptor_get_set(): + """Test property descriptor get / set.""" - def testPropertyDescriptorWrongType(self): - """Test setting a property using a value of the wrong type.""" + # This test ensures that setting an attribute implemented with + # a descriptor actually goes through the descriptor (rather than + # silently replacing the descriptor in the instance or type dict. - def test(): - object = PropertyTest() - object.PublicProperty = "spam" + ob = PropertyTest() - self.assertTrue(TypeError, test) + assert PropertyTest.PublicStaticProperty == 0 + assert ob.PublicStaticProperty == 0 - def testPropertyDescriptorAbuse(self): - """Test property descriptor abuse.""" - desc = PropertyTest.__dict__['PublicProperty'] + descriptor = PropertyTest.__dict__['PublicStaticProperty'] + assert type(descriptor) != int - def test(): - desc.__get__(0, 0) + ob.PublicStaticProperty = 0 + descriptor = PropertyTest.__dict__['PublicStaticProperty'] + assert type(descriptor) != int - self.assertRaises(TypeError, test) + PropertyTest.PublicStaticProperty = 0 + descriptor = PropertyTest.__dict__['PublicStaticProperty'] + assert type(descriptor) != int - def test(): - desc.__set__(0, 0) - self.assertRaises(TypeError, test) +def test_property_descriptor_wrong_type(): + """Test setting a property using a value of the wrong type.""" - def testInterfaceProperty(self): - """Test properties of interfaces. Added after a bug report - that an IsAbstract check was inappropriate and prevented - use of properties when only the interface is known.""" + with pytest.raises(TypeError): + ob = PropertyTest() + ob.PublicProperty = "spam" - from System.Collections import Hashtable, ICollection - mapping = Hashtable() - coll = ICollection(mapping) - self.assertTrue(coll.Count == 0) +def test_property_descriptor_abuse(): + """Test property descriptor abuse.""" + desc = PropertyTest.__dict__['PublicProperty'] -def test_suite(): - return unittest.makeSuite(PropertyTests) + with pytest.raises(TypeError): + desc.__get__(0, 0) + with pytest.raises(TypeError): + desc.__set__(0, 0) -def main(): - unittest.TextTestRunner().run(test_suite()) +def test_interface_property(): + """Test properties of interfaces. Added after a bug report + that an IsAbstract check was inappropriate and prevented + use of properties when only the interface is known.""" + from System.Collections import Hashtable, ICollection -if __name__ == '__main__': - main() + mapping = Hashtable() + coll = ICollection(mapping) + assert coll.Count == 0 diff --git a/src/tests/test_recursive_types.py b/src/tests/test_recursive_types.py new file mode 100644 index 000000000..ca4b871cf --- /dev/null +++ b/src/tests/test_recursive_types.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +"""Test if interop with recursive type inheritance works.""" + + +def test_recursive_type_creation(): + """Test that a recursive types don't crash with a + StackOverflowException""" + from Python.Test import RecursiveInheritance + + test_instance = RecursiveInheritance.SubClass() + test_instance.SomeMethod() diff --git a/src/tests/test_subclass.py b/src/tests/test_subclass.py index c486a0fc3..43d013c7c 100644 --- a/src/tests/test_subclass.py +++ b/src/tests/test_subclass.py @@ -1,175 +1,246 @@ -import clr +# -*- coding: utf-8 -*- +# FIXME: This test module randomly passes/fails even if all tests are skipped. +# Something fishy is going on with the Test fixtures. Behavior seen on CI on +# both Linux and Windows +# TODO: Remove delay of class creations. Adding SetUp/TearDown may help + +"""Test sub-classing managed types""" + +import System +import pytest +from Python.Test import (IInterfaceTest, SubClassTest, EventArgsTest, + FunctionsTest) +from System.Collections.Generic import List -clr.AddReference('Python.Test') -clr.AddReference('System') +from ._compat import range + + +def interface_test_class_fixture(subnamespace): + """Delay creation of class until test starts.""" + + class InterfaceTestClass(IInterfaceTest): + """class that implements the test interface""" + __namespace__ = "Python.Test." + subnamespace + + def foo(self): + return "InterfaceTestClass" + + def bar(self, x, i): + return "/".join([x] * i) + + return InterfaceTestClass + + +def derived_class_fixture(subnamespace): + """Delay creation of class until test starts.""" + + class DerivedClass(SubClassTest): + """class that derives from a class deriving from IInterfaceTest""" + __namespace__ = "Python.Test." + subnamespace + + def foo(self): + return "DerivedClass" + + def base_foo(self): + return SubClassTest.foo(self) + + def super_foo(self): + return super(DerivedClass, self).foo() + + def bar(self, x, i): + return "_".join([x] * i) + + def return_list(self): + l = List[str]() + l.Add("A") + l.Add("B") + l.Add("C") + return l + + return DerivedClass -import sys, os, string, unittest, types -from Python.Test import TestFunctions, SubClassTest, IInterfaceTest, TestEventArgs -from System.Collections.Generic import List -from System import NotImplementedException +def derived_event_test_class_fixture(subnamespace): + """Delay creation of class until test starts.""" -# class that implements the test interface -class InterfaceTestClass(IInterfaceTest): - __namespace__ = "Python.Test" - - def foo(self): - return "InterfaceTestClass" - - def bar(self, x, i): - return "/".join([x] * i) - - -# class that derives from a class deriving from IInterfaceTest -class DerivedClass(SubClassTest): - __namespace__ = "Python.Test" - - def foo(self): - return "DerivedClass" - - def base_foo(self): - return SubClassTest.foo(self) - - def super_foo(self): - return super(DerivedClass, self).foo() + class DerivedEventTest(IInterfaceTest): + """class that implements IInterfaceTest.TestEvent""" + __namespace__ = "Python.Test." + subnamespace - def bar(self, x, i): - return "_".join([x] * i) - - def return_list(self): - l = List[str]() - l.Add("A") - l.Add("B") - l.Add("C") - return l - - -# class that implements IInterfaceTest.TestEvent -class DerivedEventTest(IInterfaceTest): - __namespace__ = "Python.Test" - - def __init__(self): - self.event_handlers = [] - - # event handling - def add_TestEvent(self, handler): - self.event_handlers.append(handler) - - def remove_TestEvent(self, handler): - self.event_handlers.remove(handler) - - def OnTestEvent(self, value): - args = TestEventArgs(value) - for handler in self.event_handlers: - handler(self, args) + def __init__(self): + self.event_handlers = [] + # event handling + def add_TestEvent(self, handler): + self.event_handlers.append(handler) -class SubClassTests(unittest.TestCase): - """Test subclassing managed types""" + def remove_TestEvent(self, handler): + self.event_handlers.remove(handler) - def testBaseClass(self): - """Test base class managed type""" - object = SubClassTest() - self.assertEqual(object.foo(), "foo") - self.assertEqual(TestFunctions.test_foo(object), "foo") - self.assertEqual(object.bar("bar", 2), "bar") - self.assertEqual(TestFunctions.test_bar(object, "bar", 2), "bar") - self.assertEqual(object.not_overriden(), "not_overriden") - self.assertEqual(list(object.return_list()), ["a", "b", "c"]) - self.assertEqual(list(SubClassTest.test_list(object)), ["a", "b", "c"]) + def OnTestEvent(self, value): + args = EventArgsTest(value) + for handler in self.event_handlers: + handler(self, args) - def testInterface(self): - """Test python classes can derive from C# interfaces""" - object = InterfaceTestClass() - self.assertEqual(object.foo(), "InterfaceTestClass") - self.assertEqual(TestFunctions.test_foo(object), "InterfaceTestClass") - self.assertEqual(object.bar("bar", 2), "bar/bar") - self.assertEqual(TestFunctions.test_bar(object, "bar", 2), "bar/bar") + return DerivedEventTest - x = TestFunctions.pass_through(object) - self.assertEqual(id(x), id(object)) - def testDerivedClass(self): - """Test python class derived from managed type""" - object = DerivedClass() - self.assertEqual(object.foo(), "DerivedClass") - self.assertEqual(object.base_foo(), "foo") - self.assertEqual(object.super_foo(), "foo") - self.assertEqual(TestFunctions.test_foo(object), "DerivedClass") - self.assertEqual(object.bar("bar", 2), "bar_bar") - self.assertEqual(TestFunctions.test_bar(object, "bar", 2), "bar_bar") - self.assertEqual(object.not_overriden(), "not_overriden") - self.assertEqual(list(object.return_list()), ["A", "B", "C"]) - self.assertEqual(list(SubClassTest.test_list(object)), ["A", "B", "C"]) +def test_base_class(): + """Test base class managed type""" + ob = SubClassTest() + assert ob.foo() == "foo" + assert FunctionsTest.test_foo(ob) == "foo" + assert ob.bar("bar", 2) == "bar" + assert FunctionsTest.test_bar(ob, "bar", 2) == "bar" + assert ob.not_overriden() == "not_overriden" + assert list(ob.return_list()) == ["a", "b", "c"] + assert list(SubClassTest.test_list(ob)) == ["a", "b", "c"] - x = TestFunctions.pass_through(object) - self.assertEqual(id(x), id(object)) - def testCreateInstance(self): - """Test derived instances can be created from managed code""" - object = TestFunctions.create_instance(DerivedClass) - self.assertEqual(object.foo(), "DerivedClass") - self.assertEqual(TestFunctions.test_foo(object), "DerivedClass") - self.assertEqual(object.bar("bar", 2), "bar_bar") - self.assertEqual(TestFunctions.test_bar(object, "bar", 2), "bar_bar") - self.assertEqual(object.not_overriden(), "not_overriden") +def test_interface(): + """Test python classes can derive from C# interfaces""" + InterfaceTestClass = interface_test_class_fixture(test_interface.__name__) + ob = InterfaceTestClass() + assert ob.foo() == "InterfaceTestClass" + assert FunctionsTest.test_foo(ob) == "InterfaceTestClass" + assert ob.bar("bar", 2) == "bar/bar" + assert FunctionsTest.test_bar(ob, "bar", 2) == "bar/bar" - x = TestFunctions.pass_through(object) - self.assertEqual(id(x), id(object)) + x = FunctionsTest.pass_through(ob) + assert id(x) == id(ob) - object2 = TestFunctions.create_instance(InterfaceTestClass) - self.assertEqual(object2.foo(), "InterfaceTestClass") - self.assertEqual(TestFunctions.test_foo(object2), "InterfaceTestClass") - self.assertEqual(object2.bar("bar", 2), "bar/bar") - self.assertEqual(TestFunctions.test_bar(object2, "bar", 2), "bar/bar") - y = TestFunctions.pass_through(object2) - self.assertEqual(id(y), id(object2)) - - def testEvents(self): - class EventHandler: - def handler(self, x, args): - self.value = args.value - - event_handler = EventHandler() - - x = SubClassTest() - x.TestEvent += event_handler.handler - self.assertEqual(TestFunctions.test_event(x, 1), 1) - self.assertEqual(event_handler.value, 1) - - i = InterfaceTestClass() - self.assertRaises(NotImplementedException, TestFunctions.test_event, i, 2) - - d = DerivedEventTest() - d.add_TestEvent(event_handler.handler) - self.assertEqual(TestFunctions.test_event(d, 3), 3) - self.assertEqual(event_handler.value, 3) - self.assertEqual(len(d.event_handlers), 1) - - def test_isinstance(self): - from System import Object - from System import String - - a = [str(x) for x in range(0, 1000)] - b = [String(x) for x in a] - - for x in a: - self.assertFalse(isinstance(x, Object)) - self.assertFalse(isinstance(x, String)) - - for x in b: - self.assertTrue(isinstance(x, Object)) - self.assertTrue(isinstance(x, String)) - - -def test_suite(): - return unittest.makeSuite(SubClassTests) - - -def main(): - unittest.TextTestRunner().run(test_suite()) - - -if __name__ == '__main__': - main() +def test_derived_class(): + """Test python class derived from managed type""" + DerivedClass = derived_class_fixture(test_derived_class.__name__) + ob = DerivedClass() + assert ob.foo() == "DerivedClass" + assert ob.base_foo() == "foo" + assert ob.super_foo() == "foo" + assert FunctionsTest.test_foo(ob) == "DerivedClass" + assert ob.bar("bar", 2) == "bar_bar" + assert FunctionsTest.test_bar(ob, "bar", 2) == "bar_bar" + assert ob.not_overriden() == "not_overriden" + assert list(ob.return_list()) == ["A", "B", "C"] + assert list(SubClassTest.test_list(ob)) == ["A", "B", "C"] + + x = FunctionsTest.pass_through(ob) + assert id(x) == id(ob) + + +def test_create_instance(): + """Test derived instances can be created from managed code""" + DerivedClass = derived_class_fixture(test_create_instance.__name__) + ob = FunctionsTest.create_instance(DerivedClass) + assert ob.foo() == "DerivedClass" + assert FunctionsTest.test_foo(ob) == "DerivedClass" + assert ob.bar("bar", 2) == "bar_bar" + assert FunctionsTest.test_bar(ob, "bar", 2) == "bar_bar" + assert ob.not_overriden() == "not_overriden" + + x = FunctionsTest.pass_through(ob) + assert id(x) == id(ob) + + InterfaceTestClass = interface_test_class_fixture(test_create_instance.__name__) + ob2 = FunctionsTest.create_instance(InterfaceTestClass) + assert ob2.foo() == "InterfaceTestClass" + assert FunctionsTest.test_foo(ob2) == "InterfaceTestClass" + assert ob2.bar("bar", 2) == "bar/bar" + assert FunctionsTest.test_bar(ob2, "bar", 2) == "bar/bar" + + y = FunctionsTest.pass_through(ob2) + assert id(y) == id(ob2) + + +def test_events(): + class EventHandler(object): + def handler(self, x, args): + self.value = args.value + + event_handler = EventHandler() + + x = SubClassTest() + x.TestEvent += event_handler.handler + assert FunctionsTest.test_event(x, 1) == 1 + assert event_handler.value == 1 + + InterfaceTestClass = interface_test_class_fixture(test_events.__name__) + i = InterfaceTestClass() + with pytest.raises(System.NotImplementedException): + FunctionsTest.test_event(i, 2) + + DerivedEventTest = derived_event_test_class_fixture(test_events.__name__) + d = DerivedEventTest() + d.add_TestEvent(event_handler.handler) + assert FunctionsTest.test_event(d, 3) == 3 + assert event_handler.value == 3 + assert len(d.event_handlers) == 1 + + +def test_isinstance_check(): + a = [str(x) for x in range(0, 1000)] + b = [System.String(x) for x in a] + + for x in a: + assert not isinstance(x, System.Object) + assert not isinstance(x, System.String) + + for x in b: + assert isinstance(x, System.Object) + assert isinstance(x, System.String) + +def test_namespace_and_init(): + calls = [] + class TestX(System.Object): + __namespace__ = "test_clr_subclass_with_init_args" + def __init__(self, *args, **kwargs): + calls.append((args, kwargs)) + t = TestX(1,2,3,foo="bar") + assert len(calls) == 1 + assert calls[0][0] == (1,2,3) + assert calls[0][1] == {"foo":"bar"} + +def test_namespace_and_argless_init(): + calls = [] + class TestX(System.Object): + __namespace__ = "test_clr_subclass_without_init_args" + def __init__(self): + calls.append(True) + t = TestX() + assert len(calls) == 1 + assert calls[0] == True + + +def test_namespace_and_no_init(): + class TestX(System.Object): + __namespace__ = "test_clr_subclass_without_init" + q = 1 + t = TestX() + assert t.q == 1 + +def test_construction_from_clr(): + import clr + calls = [] + class TestX(System.Object): + __namespace__ = "test_clr_subclass_init_from_clr" + @clr.clrmethod(None, [int, str]) + def __init__(self, i, s): + calls.append((i, s)) + + # Construct a TestX from Python + t = TestX(1, "foo") + assert len(calls) == 1 + assert calls[0][0] == 1 + assert calls[0][1] == "foo" + + # Reset calls and construct a TestX from CLR + calls = [] + tp = t.GetType() + t2 = tp.GetConstructors()[0].Invoke(None) + assert len(calls) == 0 + + # The object has only been constructed, now it needs to be initialized as well + tp.GetMethod("__init__").Invoke(t2, [1, "foo"]) + assert len(calls) == 1 + assert calls[0][0] == 1 + assert calls[0][1] == "foo" diff --git a/src/tests/test_suite/__init__.py b/src/tests/test_suite/__init__.py deleted file mode 100644 index 5b1cc4ae4..000000000 --- a/src/tests/test_suite/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -import unittest - -__all__ = ['test_suite'] - -from .test_import import test_suite as import_tests -from .test_callback import test_suite as callback_tests -from .test_recursiveTypes import test_suite as recursiveTypes_tests - -def test_suite(): - suite = unittest.TestSuite() - suite.addTests((import_tests(),)) - suite.addTests((callback_tests(),)) - suite.addTests((recursiveTypes_tests(),)) - return suite \ No newline at end of file diff --git a/src/tests/test_suite/_missing_import.py b/src/tests/test_suite/_missing_import.py deleted file mode 100644 index 629ff95be..000000000 --- a/src/tests/test_suite/_missing_import.py +++ /dev/null @@ -1,2 +0,0 @@ - -import this_package_should_never_exist_ever \ No newline at end of file diff --git a/src/tests/test_suite/test_callback.py b/src/tests/test_suite/test_callback.py deleted file mode 100644 index 16c45914d..000000000 --- a/src/tests/test_suite/test_callback.py +++ /dev/null @@ -1,30 +0,0 @@ -import unittest, sys -import clr - -this_module = sys.modules[__name__] -clr.AddReference("Python.Test") -import Python.Test as Test -from Python.Test import CallbackTest -test_instance = CallbackTest() - -def simpleDefaultArg(arg = 'test'): - return arg - -class CallbackTests(unittest.TestCase): - """Test that callbacks from C# into python work.""" - - def testDefaultForNull(self): - """Test that C# can use null for an optional python argument""" - retVal = test_instance.Call_simpleDefaultArg_WithNull(__name__) - pythonRetVal = simpleDefaultArg(None) - self.assertEquals(retVal, pythonRetVal) - - def testDefaultForNone(self): - """Test that C# can use no argument for an optional python argument""" - retVal = test_instance.Call_simpleDefaultArg_WithEmptyArgs(__name__) - pythonRetVal = simpleDefaultArg() - self.assertEquals(retVal, pythonRetVal) - -def test_suite(): - return unittest.makeSuite(CallbackTests) - diff --git a/src/tests/test_suite/test_import.py b/src/tests/test_suite/test_import.py deleted file mode 100644 index b6d155af3..000000000 --- a/src/tests/test_suite/test_import.py +++ /dev/null @@ -1,16 +0,0 @@ -import unittest - -class ImportTests(unittest.TestCase): - """Test the import statement.""" - - def testRealtiveMissingImport(self): - """Test that a relative missing import doesn't crash. Some modules use this to check if a package is installed (realtive import in the site-packages folder""" - try: - from . import _missing_import - except ImportError: - pass - - -def test_suite(): - return unittest.makeSuite(ImportTests) - diff --git a/src/tests/test_suite/test_recursiveTypes.py b/src/tests/test_suite/test_recursiveTypes.py deleted file mode 100644 index 290d7236a..000000000 --- a/src/tests/test_suite/test_recursiveTypes.py +++ /dev/null @@ -1,20 +0,0 @@ -import unittest, sys -import clr - -this_module = sys.modules[__name__] -clr.AddReference("Python.Test") -class RecursiveTypesTests(unittest.TestCase): - """Test if interop with recursive type inheritance works.""" - - def testRecursiveTypeCreation(self): - """Test that a recursive types don't crash with a StackOverflowException""" - import Python.Test as Test - from Python.Test import RecursiveInheritance - test_instance = RecursiveInheritance.SubClass() - test_instance.SomeMethod() - pass - - -def test_suite(): - return unittest.makeSuite(RecursiveTypesTests) - diff --git a/src/tests/test_sysargv.py b/src/tests/test_sysargv.py new file mode 100644 index 000000000..d86aa1c1d --- /dev/null +++ b/src/tests/test_sysargv.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +"""Test sys.argv state.""" + +import sys + +from ._compat import check_output + + +def test_sys_argv_state(filepath): + """Test sys.argv state doesn't change after clr import. + To better control the arguments being passed, test on a fresh python + instance with specific arguments""" + + script = filepath("argv-fixture.py") + out = check_output([sys.executable, script, "foo", "bar"]) + assert "foo" in out + assert "bar" in out diff --git a/src/tests/test_thread.py b/src/tests/test_thread.py index 67873d83c..c62c15939 100644 --- a/src/tests/test_thread.py +++ b/src/tests/test_thread.py @@ -1,75 +1,58 @@ -import sys, os, string, unittest, types -from Python.Test import ThreadTest -import six - -if six.PY3: - import _thread as thread -else: - import thread - - -def dprint(msg): - # Debugging helper to trace thread-related tests. - if 0: print(msg) - - -class ThreadTests(unittest.TestCase): - """Test CLR bridge threading and GIL handling.""" - - def testSimpleCallbackToPython(self): - """Test a call to managed code that then calls back into Python.""" - dprint("thread %s SimpleCallBack" % thread.get_ident()) - result = ThreadTest.CallEchoString("spam") - self.assertTrue(result == "spam") - dprint("thread %s SimpleCallBack ret" % thread.get_ident()) - - def testDoubleCallbackToPython(self): - """Test a call to managed code that then calls back into Python - that then calls managed code that then calls Python again.""" - dprint("thread %s DoubleCallBack" % thread.get_ident()) - result = ThreadTest.CallEchoString2("spam") - self.assertTrue(result == "spam") - dprint("thread %s DoubleCallBack ret" % thread.get_ident()) - - def testPythonThreadCallsToCLR(self): - """Test calls by Python-spawned threads into managed code.""" - # This test is very likely to hang if something is wrong ;) - import threading, time - from System import String - - done = [] - - def run_thread(): - for i in range(10): - time.sleep(0.1) - dprint("thread %s %d" % (thread.get_ident(), i)) - mstr = String("thread %s %d" % (thread.get_ident(), i)) - pstr = mstr.ToString() - done.append(None) - dprint("thread %s %d done" % (thread.get_ident(), i)) - - def start_threads(count): - for i in range(count): - thread = threading.Thread(target=run_thread) - thread.start() - - start_threads(5) - - while len(done) < 50: - dprint(len(done)) - time.sleep(0.1) +# -*- coding: utf-8 -*- + +"""Test CLR bridge threading and GIL handling.""" + +import threading +import time + +from ._compat import range, thread +from .utils import dprint - return +def test_simple_callback_to_python(): + """Test a call to managed code that then calls back into Python.""" + from Python.Test import ThreadTest -def test_suite(): - return unittest.makeSuite(ThreadTests) + dprint("thread %s SimpleCallBack" % thread.get_ident()) + result = ThreadTest.CallEchoString("spam") + assert result == "spam" + dprint("thread %s SimpleCallBack ret" % thread.get_ident()) -def main(): - for i in range(50): - unittest.TextTestRunner().run(test_suite()) +def test_double_callback_to_python(): + """Test a call to managed code that then calls back into Python + that then calls managed code that then calls Python again.""" + from Python.Test import ThreadTest + dprint("thread %s DoubleCallBack" % thread.get_ident()) + result = ThreadTest.CallEchoString2("spam") + assert result == "spam" + dprint("thread %s DoubleCallBack ret" % thread.get_ident()) -if __name__ == '__main__': - main() + +def test_python_thread_calls_to_clr(): + """Test calls by Python-spawned threads into managed code.""" + # This test is very likely to hang if something is wrong ;) + import System + + done = [] + + def run_thread(): + for i in range(10): + time.sleep(0.1) + dprint("thread %s %d" % (thread.get_ident(), i)) + mstr = System.String("thread %s %d" % (thread.get_ident(), i)) + dprint(mstr.ToString()) + done.append(None) + dprint("thread %s %d done" % (thread.get_ident(), i)) + + def start_threads(count): + for _ in range(count): + thread_ = threading.Thread(target=run_thread) + thread_.start() + + start_threads(5) + + while len(done) < 50: + dprint(len(done)) + time.sleep(0.1) diff --git a/src/tests/tests.pyproj b/src/tests/tests.pyproj new file mode 100644 index 000000000..cefa0d05e --- /dev/null +++ b/src/tests/tests.pyproj @@ -0,0 +1,70 @@ + + + + Debug + 2.0 + {250c535c-c060-4f0c-bd80-41f2bf373565} + + runtests.py + ..\..\ + . + . + {888888a0-9f3d-457c-b088-3a5042f75d52} + Standard Python launcher + + + + + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/tests/utils.py b/src/tests/utils.py new file mode 100644 index 000000000..cacb015ec --- /dev/null +++ b/src/tests/utils.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- + +"""Tests Utilities + +Refactor utility functions and classes +""" + +from __future__ import print_function + +from ._compat import PY2, PY3 + + +def dprint(msg): + # Debugging helper to trace thread-related tests. + if 0: + print(msg) + + +def is_clr_module(ob): + return type(ob).__name__ == 'ModuleObject' + + +def is_clr_root_module(ob): + if PY3: + # in Python 3 the clr module is a normal python module + return ob.__name__ == "clr" + elif PY2: + return type(ob).__name__ == 'CLRModule' + + +def is_clr_class(ob): + return type(ob).__name__ == 'CLR Metatype' # for now + + +class ClassicClass: + def kind(self): + return "classic" + + +class NewStyleClass(object): + def kind(self): + return "new-style" + + +class GenericHandler(object): + """A generic handler to test event callbacks.""" + + def __init__(self): + self.value = None + + def handler(self, sender, args): + self.value = args.value + + +class VariableArgsHandler(object): + """A variable args handler to test event callbacks.""" + + def __init__(self): + self.value = None + + def handler(self, *args): + ob, eventargs = args + self.value = eventargs.value + + +class CallableHandler(object): + """A callable handler to test event callbacks.""" + + def __init__(self): + self.value = None + + def __call__(self, sender, args): + self.value = args.value + + +class VarCallableHandler(object): + """A variable args callable handler to test event callbacks.""" + + def __init__(self): + self.value = None + + def __call__(self, *args): + ob, eventargs = args + self.value = eventargs.value + + +class StaticMethodHandler(object): + """A static method handler to test event callbacks.""" + + value = None + + def handler(sender, args): + StaticMethodHandler.value = args.value + + handler = staticmethod(handler) + + +class ClassMethodHandler(object): + """A class method handler to test event callbacks.""" + + value = None + + def handler(cls, sender, args): + cls.value = args.value + + handler = classmethod(handler) + + +class MultipleHandler(object): + """A generic handler to test multiple callbacks.""" + + def __init__(self): + self.value = 0 + + def handler(self, sender, args): + self.value += args.value + + def count(self): + self.value += 1 + return 'ok' + + +class HelloClass(object): + def hello(self): + return "hello" + + def __call__(self): + return "hello" + + @staticmethod + def s_hello(): + return "hello" + + @classmethod + def c_hello(cls): + return "hello" + + +def hello_func(): + return "hello" diff --git a/src/tests/warnfilter.py b/src/tests/warnfilter.py deleted file mode 100644 index 8e378b86c..000000000 --- a/src/tests/warnfilter.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Warnfilter -""" - -from warnings import filterwarnings -from warnings import resetwarnings - - -def addClrWarnfilter(action="ignore", append=False): - msgs = ["^The CLR module is deprecated.*", "^Importing from the CLR\.\* namespace.*"] - for msg in msgs: - filterwarnings(action, msg, category=DeprecationWarning, append=append) diff --git a/tools/geninterop/geninterop.py b/tools/geninterop/geninterop.py index 946e30217..bf5fdb96b 100644 --- a/tools/geninterop/geninterop.py +++ b/tools/geninterop/geninterop.py @@ -15,16 +15,19 @@ from __future__ import print_function -from distutils.sysconfig import get_config_var -from subprocess import Popen, CalledProcessError, PIPE -from pycparser import c_parser, c_ast import logging -import sys import os +import sys +import sysconfig +import subprocess + +from pycparser import c_ast, c_parser _log = logging.getLogger() logging.basicConfig(level=logging.DEBUG) +PY_MAJOR = sys.version_info[0] +PY_MINOR = sys.version_info[1] # rename some members from their C name when generating the C# _typeoffset_member_renames = { @@ -33,6 +36,14 @@ } +def _check_output(*args, **kwargs): + """Check output wrapper for py2/py3 compatibility""" + output = subprocess.check_output(*args, **kwargs) + if PY_MAJOR == 2: + return output + return output.decode("ascii") + + class AstParser(object): """Walk an AST and determine the members of all structs""" @@ -147,23 +158,6 @@ def __get_struct_name(self, node): return node.name or "_struct_%d" % id(node) -def check_output(*popenargs, **kwargs): - """subprocess.check_output from python 2.7. - Added here to support building for earlier versions of Python. - """ - process = Popen(stdout=PIPE, *popenargs, **kwargs) - output, unused_err = process.communicate() - retcode = process.poll() - if retcode: - cmd = kwargs.get("args") - if cmd is None: - cmd = popenargs[0] - raise CalledProcessError(retcode, cmd) - if sys.version_info[0] > 2: - return output.decode("ascii") - return output - - def preprocess_python_headers(): """Return Python.h pre-processed, ready for parsing. Requires clang. @@ -172,7 +166,7 @@ def preprocess_python_headers(): "fake_libc_include") include_dirs = [fake_libc_include] - include_py = get_config_var("INCLUDEPY") + include_py = sysconfig.get_config_var("INCLUDEPY") include_dirs.append(include_py) defines = [ @@ -195,7 +189,7 @@ def preprocess_python_headers(): # normalize as the parser doesn't like windows line endings. lines = [] - for line in check_output(cmd).splitlines(): + for line in _check_output(cmd).splitlines(): if line.startswith("#"): line = line.replace("\\", "/") lines.append(line) @@ -206,7 +200,7 @@ def gen_interop_code(members): """Generate the TypeOffset C# class""" defines = [ - "PYTHON%d%d" % (sys.version_info[:2]) + "PYTHON{0}{1}".format(PY_MAJOR, PY_MINOR) ] if hasattr(sys, "abiflags"): @@ -217,6 +211,8 @@ def gen_interop_code(members): if "u" in sys.abiflags: defines.append("PYTHON_WITH_WIDE_UNICODE") + filename = os.path.basename(__file__) + defines_str = " && ".join(defines) class_definition = """ // Auto-generated by %s. // DO NOT MODIFIY BY HAND. @@ -252,7 +248,7 @@ def gen_interop_code(members): } // Auto-generated from PyHeapTypeObject in Python.h -""" % (os.path.basename(__file__), " && ".join(defines)) +""" % (filename, defines_str) # All the members are sizeof(void*) so we don't need to do any # extra work to determine the size based on the type. diff --git a/tools/nuget/nuget.exe b/tools/nuget/nuget.exe index e42e6d827..463f8e137 100644 Binary files a/tools/nuget/nuget.exe and b/tools/nuget/nuget.exe differ diff --git a/tools/vswhere/vswhere.exe b/tools/vswhere/vswhere.exe new file mode 100644 index 000000000..3eb2df009 Binary files /dev/null and b/tools/vswhere/vswhere.exe differ diff --git a/tox.ini b/tox.ini new file mode 100644 index 000000000..3c9be5c63 --- /dev/null +++ b/tox.ini @@ -0,0 +1,27 @@ +[tox] +skip_missing_interpreters=True +envlist = + py27 + py33 + py34 + py35 + py36 + py37 + check + +[testenv] +deps = + pytest +commands = + {posargs:py.test} + +[testenv:check] +ignore_errors=True +skip_install=True +basepython=python3.5 +deps = + check-manifest + flake8 +commands = + flake8 src setup.py + python setup.py check --strict --metadata