Skip to content

Commit

Permalink
Merge branch 'pr/allchanges' into rhino-8.x
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/runtime/Converter.cs
  • Loading branch information
eirannejad committed Dec 8, 2023
2 parents 18c55fc + 8054a12 commit 56150fb
Show file tree
Hide file tree
Showing 28 changed files with 432 additions and 143 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/ARM.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,25 @@ jobs:
- name: Install dependencies
run: |
pip install --upgrade -r requirements.txt
pip install pytest numpy # for tests
pip3.8 install -r requirements.txt
pip3.8 install pytest numpy # for tests
- name: Build and Install
run: |
pip install -v .
pip3.8 install -v .
- name: Set Python DLL path (non Windows)
run: |
echo PYTHONNET_PYDLL=$(python -m find_libpython) >> $GITHUB_ENV
echo PYTHONNET_PYDLL=$(python3.8 -m find_libpython) >> $GITHUB_ENV
- name: Embedding tests
run: dotnet test --logger "console;verbosity=detailed" src/embed_tests/

- name: Python Tests (Mono)
run: python -m pytest --runtime mono
run: python3.8 -m pytest --runtime mono

- name: Python Tests (.NET Core)
run: python -m pytest --runtime coreclr
run: python3.8 -m pytest --runtime coreclr

- name: Python tests run from .NET
run: dotnet test src/python_tests_runner/
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
fail-fast: false
matrix:
os: [windows, ubuntu, macos]
python: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
platform: [x64, x86]
exclude:
- os: ubuntu
Expand Down
1 change: 1 addition & 0 deletions AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,4 @@
- ([@alxnull](https://github.com/alxnull))
- ([@gpetrou](https://github.com/gpetrou))
- Ehsan Iran-Nejad ([@eirannejad](https://github.com/eirannejad))
- ([@legomanww](https://github.com/legomanww))
14 changes: 11 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@ project adheres to [Semantic Versioning][].

This document follows the conventions laid out in [Keep a CHANGELOG][].

## [Unreleased][]
## [3.0.3](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.3) - 2023-10-11

### Added

- Added support for automatically casting callables as Delegate when passed as argument to a Managed method ([#2015][p2015]).
- Support for Python 3.12

### Changed

- Use enum name in `repr`

## [3.0.2](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.2) - 2023-08-29

### Fixed

- Fixed error occuring when inheriting a class containing a virtual generic method.
- Fixed error occuring when inheriting a class containing a virtual generic method
- Make a second call to `pythonnet.load` a no-op, as it was intended
- Added support for multiple inheritance when inheriting from a class and/or multiple interfaces
- Fixed error occuring when calling `GetBuffer` for anything other than `PyBUF.SIMPLE`
- Bumped `clr_loader` dependency to incorporate patches

## [3.0.1](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.1) - 2022-11-03

Expand Down
3 changes: 3 additions & 0 deletions doc/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ pygments>=2.7
# C# via doxygen
breathe
git+https://github.com/rogerbarton/sphinx-csharp.git

# Dependency of pythonnet, needed for autodocs
clr_loader
43 changes: 27 additions & 16 deletions doc/source/dotnet.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ to:

- Reference ``Python.Runtime.dll`` (e.g. via a ``PackageReference``)
- Call ``PythonEngine.Initialize()`` to initialize Python
- Call ``PythonEngine.ImportModule(name)`` to import a module
- Call ``var mod = PyModule.Import(name)`` to import a module as ``mod``

The module you import can either start working with your managed app
environment at the time its imported, or you can explicitly lookup and
Expand All @@ -42,28 +42,39 @@ application.

Before interacting with any of the objects or APIs provided by the
``Python.Runtime`` namespace, calling code must have acquired the Python
global interpreter lock by calling the ``PythonEngine.AcquireLock``
method. The only exception to this rule is the
``PythonEngine.Initialize`` method, which may be called at startup
without having acquired the GIL.

When finished using Python APIs, managed code must call a corresponding
``PythonEngine.ReleaseLock`` to release the GIL and allow other threads
to use Python.

A ``using`` statement may be used to acquire and release the GIL:
global interpreter lock by ``using'' ``Py.GIL()``. The only exception to
this rule is the ``PythonEngine.Initialize`` method, which may be called
at startup without having acquired the GIL. The GIL is released again
by disposing the return value of `Py.GIL()`:

.. code:: csharp
using (Py.GIL())
{
PythonEngine.Exec("doStuff()");
}
// or
{
using var _ = Py.GIL()
PythonEngine.Exec("doStuff()");
}
// or
var gil = Py.GIL();
try
{
PythonEngine.Exec("doStuff()");
}
finally
{
gil.Dispose();
}
The AcquireLock and ReleaseLock methods are thin wrappers over the
unmanaged ``PyGILState_Ensure`` and ``PyGILState_Release`` functions
from the Python API, and the documentation for those APIs applies to the
managed versions.
The ``Py.GIL()'' object is a thin wrapper over the unmanaged
``PyGILState_Ensure`` (on construction) and ``PyGILState_Release`` (on
disposal) functions from the Python API, and the documentation for those
APIs applies to the managed versions.

Passing C# Objects to the Python Engine
---------------------------------------
Expand Down Expand Up @@ -99,7 +110,7 @@ Code executed from the scope will have access to the variable:
using (Py.GIL())
{
// create a Python scope
using (PyScope scope = Py.CreateScope())
using (PyModule scope = Py.CreateScope())
{
// convert the Person object to a PyObject
PyObject pyPerson = person.ToPython();
Expand Down
6 changes: 4 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ license = {text = "MIT"}
readme = "README.rst"

dependencies = [
"clr_loader>=0.2.2,<0.3.0"
"clr_loader>=0.2.6,<0.3.0"
]

requires-python = ">=3.7, <3.12"
requires-python = ">=3.7, <3.13"

classifiers = [
"Development Status :: 5 - Production/Stable",
Expand All @@ -26,6 +26,7 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
"Operating System :: MacOS :: MacOS X",
Expand All @@ -50,6 +51,7 @@ file = "version.txt"

[tool.setuptools.packages.find]
include = ["pythonnet*"]
exclude = [".gitignore"]

[tool.pytest.ini_options]
xfail_strict = true
Expand Down
6 changes: 5 additions & 1 deletion pythonnet/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ def load(runtime: Union[clr_loader.Runtime, str, None] = None, **params: str) ->
The same parameters as for `set_runtime` can be used. By default,
`set_default_runtime` is called if no environment has been set yet and no
parameters are passed."""
parameters are passed.
After a successful call, further invocations will return immediately."""
global _LOADED, _LOADER_ASSEMBLY

if _LOADED:
Expand All @@ -142,6 +144,8 @@ def load(runtime: Union[clr_loader.Runtime, str, None] = None, **params: str) ->

if func(b"") != 0:
raise RuntimeError("Failed to initialize Python.Runtime.dll")

_LOADED = True

import atexit

Expand Down
5 changes: 2 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ codecov

wheel
pycparser
setuptools
clr-loader
clr-loader==0.2.*

# Discover libpython
find_libpython
find_libpython==0.3.*
22 changes: 17 additions & 5 deletions src/embed_tests/Codecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -371,11 +371,23 @@ public void FloatDerivedDecoded()
[Test]
public void ExceptionDecodedNoInstance()
{
PyObjectConversions.RegisterDecoder(new InstancelessExceptionDecoder());
using var scope = Py.CreateScope();
var error = Assert.Throws<ValueErrorWrapper>(() => PythonEngine.Exec(
$"[].__iter__().__next__()"));
Assert.AreEqual(TestExceptionMessage, error.Message);
if (Runtime.PyVersion < new Version(3, 12))
{
PyObjectConversions.RegisterDecoder(new InstancelessExceptionDecoder());
using var scope = Py.CreateScope();

var error = Assert.Throws<ValueErrorWrapper>(() =>
PythonEngine.Exec($"[].__iter__().__next__()")
);
Assert.AreEqual(TestExceptionMessage, error.Message);
}
else
{
Assert.Ignore(
"This test does not work for Python 3.12, see " +
"https://github.com/python/cpython/issues/101578"
);
}
}

public static void AcceptsDateTime(DateTime v) {}
Expand Down
36 changes: 36 additions & 0 deletions src/embed_tests/TestPyBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,26 @@ public void Finalization()
Assert.AreEqual(1, arr.Refcount);
}

[Test]
public void MultidimensionalNumPyArray()
{
var ndarray = np.arange(24).reshape(1,2,3,4).T;
PyObject ndim = ndarray.ndim;
PyObject shape = ndarray.shape;
PyObject strides = ndarray.strides;
PyObject contiguous = ndarray.flags["C_CONTIGUOUS"];

using PyBuffer buf = ndarray.GetBuffer(PyBUF.STRIDED);

Assert.Multiple(() =>
{
Assert.That(buf.Dimensions, Is.EqualTo(ndim.As<int>()));
Assert.That(buf.Shape, Is.EqualTo(shape.As<long[]>()));
Assert.That(buf.Strides, Is.EqualTo(strides.As<long[]>()));
Assert.That(buf.IsContiguous(BufferOrderStyle.C), Is.EqualTo(contiguous.As<bool>()));
});
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void MakeBufAndLeak(PyObject bufProvider)
{
Expand All @@ -121,5 +141,21 @@ static PyObject ByteArrayFromAsciiString(string str)
using var scope = Py.CreateScope();
return Runtime.Runtime.PyByteArray_FromStringAndSize(str).MoveToPyObject();
}

dynamic np
{
get
{
try
{
return Py.Import("numpy");
}
catch (PythonException)
{
Assert.Inconclusive("Numpy or dependency not installed");
return null;
}
}
}
}
}
1 change: 1 addition & 0 deletions src/python_tests_runner/PythonTestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static IEnumerable<string[]> PythonTestCases()
// Add the test that you want to debug here.
yield return new[] { "test_indexer", "test_boolean_indexer" };
yield return new[] { "test_delegate", "test_bool_delegate" };
yield return new[] { "test_subclass", "test_implement_interface_and_class" };
}

/// <summary>
Expand Down
8 changes: 3 additions & 5 deletions src/runtime/Converter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ internal static bool ToManagedValue(BorrowedReference value, Type obType,
var arrayType = Array.CreateInstance(elementType, 0).GetType();
return ToArray(value, arrayType, out result, setError);
}

// Convert python iterables to IEnumerable argument
if (obType == typeof(IEnumerable))
{
Expand Down Expand Up @@ -721,10 +721,8 @@ internal static bool ToPrimitive(BorrowedReference value, Type obType, out objec
{
if (Runtime.PyUnicode_GetLength(value) == 1)
{
IntPtr unicodePtr = Runtime.PyUnicode_AsUnicode(value);
Char[] buff = new Char[1];
Marshal.Copy(unicodePtr, buff, 0, 1);
result = buff[0];
int chr = Runtime.PyUnicode_ReadChar(value, 0);
result = (Char)chr;
return true;
}
goto type_error;
Expand Down
Loading

0 comments on commit 56150fb

Please sign in to comment.