Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove the dependency on Python.NET #72

Merged
merged 124 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
124 commits
Select commit Hold shift + click to select a range
ce0a242
Start layout for CPython API
tonybaloney Aug 6, 2024
6fde59b
Unsafe!
tonybaloney Aug 6, 2024
0b83d50
merge main
tonybaloney Aug 6, 2024
dc97bf2
Start a PInvoke/LibraryImport wrapper for CPython
tonybaloney Aug 6, 2024
70bc507
Start work migrating the initialization process.
tonybaloney Aug 6, 2024
e7422c6
Environment loading. And Py_SetPath
tonybaloney Aug 6, 2024
bf075aa
Use intptr for single byte char to string.
tonybaloney Aug 6, 2024
575b6ef
Implement custom marshallers for statically allocated ASCII strings. …
tonybaloney Aug 6, 2024
e748321
Implement high level call protocol, tuple packing, unicode conversion…
tonybaloney Aug 6, 2024
ec14778
Implement disposable GIL acquisition
tonybaloney Aug 6, 2024
1b8efda
Create convertors for common types
tonybaloney Aug 7, 2024
ee6ac96
I never said I could spell
aaronpowell Aug 7, 2024
985a57a
Registration of Python convertors
aaronpowell Aug 7, 2024
e832257
Add bool convertors and API calls. Fix double and long nullability.
tonybaloney Aug 7, 2024
f7b7d36
Add exception APIs
tonybaloney Aug 7, 2024
ff08e51
TryAdd to avoid duplicate additional convertor registrations
aaronpowell Aug 7, 2024
9421246
Create a new test project
tonybaloney Aug 7, 2024
d22a6ce
Removing generics from the Convertor API
aaronpowell Aug 7, 2024
b06d20a
Merge branch 'libraryimport' of https://github.com/tonybaloney/CSnake…
aaronpowell Aug 7, 2024
f6a9ba1
Merge branch 'libraryimport' into libraryimport-converter-pipe
aaronpowell Aug 7, 2024
e3b08a2
Store type objects in the assembly and write custom type checks.
tonybaloney Aug 7, 2024
0d47d52
Merge remote-tracking branch 'origin/libraryimport' into libraryimpor…
aaronpowell Aug 7, 2024
c94a0e4
Test long convertor
tonybaloney Aug 7, 2024
0ac994c
Add statics for list types.
tonybaloney Aug 7, 2024
27525fc
Fix the bool conversion code
tonybaloney Aug 7, 2024
57bf9b4
Partially fix the long conversion
tonybaloney Aug 7, 2024
cd8ebce
Merge remote-tracking branch 'origin/libraryimport' into libraryimpor…
aaronpowell Aug 7, 2024
7d633fe
Add ToString to PyObject
tonybaloney Aug 7, 2024
f951a3e
Removing most of the old style converters
aaronpowell Aug 7, 2024
0baa8da
Longer longs!
tonybaloney Aug 7, 2024
f6415b9
Merge remote-tracking branch 'origin/libraryimport' into libraryimpor…
aaronpowell Aug 7, 2024
aa56591
Merge remote-tracking branch 'origin/libraryimport' into libraryimpor…
aaronpowell Aug 7, 2024
494bcd8
Implementing Tuple converter
aaronpowell Aug 7, 2024
6454df7
Merge pull request #73 from tonybaloney/libraryimport-converter-pipe
aaronpowell Aug 7, 2024
6d4aacc
Removing old converter registration
aaronpowell Aug 7, 2024
4bcc979
List converter tests passing
aaronpowell Aug 7, 2024
6443daa
Fix the bool convertor.
tonybaloney Aug 7, 2024
22cba55
Initialize type pointers to zero and make them all private. Add the N…
tonybaloney Aug 7, 2024
ec4cd6b
Convert nulls to PyNone
tonybaloney Aug 7, 2024
6601f34
Remove converter injector code from source generator.
tonybaloney Aug 7, 2024
d019aee
Use the new converter code in the source gen
tonybaloney Aug 7, 2024
ab10445
Dictionary converter + removing old converter stuff
aaronpowell Aug 7, 2024
89b05bd
Don't need a converter namespace anymore
aaronpowell Aug 7, 2024
59c8846
Get some of the integration tests running
tonybaloney Aug 7, 2024
938da3b
Remove redundant test file
tonybaloney Aug 7, 2024
4498469
Add a couple of bonus long tests
tonybaloney Aug 7, 2024
19aa798
Merge branch 'libraryimport' of https://github.com/tonybaloney/CSnake…
aaronpowell Aug 7, 2024
1386229
Fixing naming
aaronpowell Aug 7, 2024
ef61205
Cache the types
aaronpowell Aug 7, 2024
d9d1306
Removing old code
aaronpowell Aug 7, 2024
a482efc
Fixing a bunch of real-world scenarios
aaronpowell Aug 7, 2024
c256dd0
Splitting the tests up so they are easier to see what is failing
aaronpowell Aug 7, 2024
93a7360
More accurate exception thrown
aaronpowell Aug 7, 2024
e2d3978
Forgot to start reading process output and error stream
aaronpowell Aug 7, 2024
70d4f3a
Version bump
aaronpowell Aug 7, 2024
a7dcc6d
Check double free
tonybaloney Aug 8, 2024
32b0a17
Store module reference once per instance rather than each call. Relea…
tonybaloney Aug 8, 2024
d090f11
Make a crashing test
tonybaloney Aug 8, 2024
bf59c9a
Raise a specific NRE for failed pyobjects.
tonybaloney Aug 8, 2024
ae32d9a
Raise Python exceptions in the CLR.
tonybaloney Aug 8, 2024
f091695
Change path init order and catch exceptions on setting path
tonybaloney Aug 8, 2024
647a340
Update dotnet-ci.yml
tonybaloney Aug 8, 2024
9e09d1f
Move set path
tonybaloney Aug 8, 2024
95b61c8
Merge branch 'libraryimport' of github.com:tonybaloney/CSnakes into l…
tonybaloney Aug 8, 2024
2bb672d
Try LPT string for platform independent paths
tonybaloney Aug 8, 2024
a3477ba
Implement a UTF32 string marshaller and use it for non-Windows enviro…
tonybaloney Aug 8, 2024
0f3aee6
Add a macOS installer locator
tonybaloney Aug 8, 2024
eb6c55e
Use the macOS locator on integration testing
tonybaloney Aug 8, 2024
7e31d5a
test macOS 13
tonybaloney Aug 8, 2024
43f8a32
deinitialize Python
tonybaloney Aug 8, 2024
4445772
Using the python finalizer and shutting down cleaner
aaronpowell Aug 8, 2024
473af5b
Set safehandle ref to null once disposed. Assert valid handles on calls.
tonybaloney Aug 8, 2024
552c46a
Add descriptions to bool, call and dict APIs about references. Wrap P…
tonybaloney Aug 8, 2024
cdaad9f
Dispose of dictionary conversion properly
tonybaloney Aug 8, 2024
49f94fa
Audit the list functions and create new reference wrappers.
tonybaloney Aug 8, 2024
41223ff
Audit tuple and dict functions. Add ref to dict item on setitem call.…
tonybaloney Aug 8, 2024
c476d35
Ensure Type() is a new reference as it returns a PyObject
tonybaloney Aug 8, 2024
e607eb6
More comments for the object methods.
tonybaloney Aug 8, 2024
9a81cd7
Handle ToString exceptions
tonybaloney Aug 8, 2024
cdb5caa
Removing unused usings
tonybaloney Aug 8, 2024
1ab5256
Better using usage
aaronpowell Aug 8, 2024
0e486ba
formatting
aaronpowell Aug 8, 2024
b7ab89c
Dispose exceptions on exit
tonybaloney Aug 8, 2024
9325679
Add a little debug helpr and change the strings abit
tonybaloney Aug 8, 2024
d79bb3b
Add GIL wrappers to the PyObject internal methods.
tonybaloney Aug 8, 2024
9a9b6d2
Add ref to dict key on successful PyDict_SetItem
tonybaloney Aug 8, 2024
1163b78
Use list append. simplify list casting. Add debug helpers.
tonybaloney Aug 9, 2024
5ac4bd2
Ensure decref is run within a GIL
tonybaloney Aug 9, 2024
ae9e6bc
Assert that Python is initialized when running release handle.
tonybaloney Aug 9, 2024
c1bcd9c
Check that Python is running when calling anything which requires the…
tonybaloney Aug 9, 2024
8df5e2e
Use a thread lock on the initialization call for Python
tonybaloney Aug 9, 2024
c5e90f8
Refactor the tests to not use a collection
aaronpowell Aug 9, 2024
3f39d7b
Hold the lock for the whole initialization script
tonybaloney Aug 9, 2024
24b25ea
Acquire GIL from all conversion tests for parallel execution.
tonybaloney Aug 9, 2024
1d670e0
Refactor the tests to not use a collection
aaronpowell Aug 9, 2024
d33bba3
Merge branch 'libraryimport' of https://github.com/tonybaloney/CSnake…
aaronpowell Aug 9, 2024
8822f4f
Set path inside the initialization lock
tonybaloney Aug 9, 2024
12fe30d
Merge branch 'libraryimport' of github.com:tonybaloney/CSnakes into l…
tonybaloney Aug 9, 2024
d2197f1
Lock finalizer
tonybaloney Aug 9, 2024
85c5099
Using a singleton better for PythonEnvironment
aaronpowell Aug 9, 2024
3a4bd3a
Add a CPython Source locator for Windows to help with debugging
tonybaloney Aug 9, 2024
f363eec
Merge branch 'libraryimport' of github.com:tonybaloney/CSnakes into l…
tonybaloney Aug 9, 2024
7aa14be
Acquire exception state inside a GIL
tonybaloney Aug 9, 2024
85b783c
In the generated code, add a debug assert that the environment hasn't…
tonybaloney Aug 9, 2024
06d3f9a
Adding logging down the stack
aaronpowell Aug 9, 2024
6470445
Dont release invalid handles. Validate GIL state checks
tonybaloney Aug 10, 2024
2e41a95
Merge logging updates
tonybaloney Aug 10, 2024
2ede4f9
Don't force Python environment disposal from the test base class
tonybaloney Aug 10, 2024
a2eb2e5
Capture a free threaded build flag.
tonybaloney Aug 11, 2024
5a7aa98
macOS source locations
tonybaloney Aug 12, 2024
a9f23e6
Undo most of the GIL changes
tonybaloney Aug 12, 2024
609b79b
Add some more threading API calls
tonybaloney Aug 12, 2024
37e6472
Remove debug noise and specifically release ceval lock from the first…
tonybaloney Aug 12, 2024
da7fcaa
Remove redundant C-API signatures.
tonybaloney Aug 12, 2024
81e1f0c
Don't run init in a special thread, it was just the eval release lock…
tonybaloney Aug 12, 2024
ba45ddd
Remove personal changes to load local python builds
tonybaloney Aug 12, 2024
0d2ef1f
Don't run integration tests in parallel for now.
tonybaloney Aug 12, 2024
591ab88
xunit settings
tonybaloney Aug 12, 2024
5470fd7
Use a different API for GIL release from the main thread
tonybaloney Aug 12, 2024
c0267d1
Add load test for sample project. re-enable parallel test collections…
tonybaloney Aug 13, 2024
132db03
Remove PyObjectStruct and pointer casting. Use concrete API calls to …
tonybaloney Aug 13, 2024
f4338cb
Code cleanup
tonybaloney Aug 13, 2024
7d1dd23
Fixing capturing warning
aaronpowell Aug 13, 2024
f2fd27e
Some little bits of cleanup
aaronpowell Aug 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/dotnet-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ jobs:
build:
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
os: [windows-latest, ubuntu-latest, macos-13, macos-latest]
python: ["3.12"]
fail-fast: false
runs-on: "${{ matrix.os }}"

steps:
Expand Down
161 changes: 161 additions & 0 deletions samples/WebApp/loadtest.jmx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.6.3">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan">
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables">
<collectionProp name="Arguments.arguments"/>
</elementProp>
</TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group">
<intProp name="ThreadGroup.num_threads">50</intProp>
<intProp name="ThreadGroup.ramp_time">1</intProp>
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller">
<stringProp name="LoopController.loops">50</stringProp>
<boolProp name="LoopController.continue_forever">false</boolProp>
</elementProp>
</ThreadGroup>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="/quick/names (Python)">
<stringProp name="HTTPSampler.domain">localhost</stringProp>
<stringProp name="HTTPSampler.port">5117</stringProp>
<stringProp name="HTTPSampler.path">/quick/names</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.postBodyRaw">false</boolProp>
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables">
<collectionProp name="Arguments.arguments"/>
</elementProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="/ (.NET)">
<stringProp name="HTTPSampler.domain">localhost</stringProp>
<stringProp name="HTTPSampler.port">5117</stringProp>
<stringProp name="HTTPSampler.path">/</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.postBodyRaw">false</boolProp>
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables">
<collectionProp name="Arguments.arguments"/>
</elementProp>
</HTTPSamplerProxy>
<hashTree/>
</hashTree>
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>true</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<sentBytes>true</sentBytes>
<url>true</url>
<threadCounts>true</threadCounts>
<idleTime>true</idleTime>
<connectTime>true</connectTime>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregate Report">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>true</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<sentBytes>true</sentBytes>
<url>true</url>
<threadCounts>true</threadCounts>
<idleTime>true</idleTime>
<connectTime>true</connectTime>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="RespTimeGraphVisualizer" testclass="ResultCollector" testname="Response Time Graph">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>true</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<sentBytes>true</sentBytes>
<url>true</url>
<threadCounts>true</threadCounts>
<idleTime>true</idleTime>
<connectTime>true</connectTime>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</jmeterTestPlan>
33 changes: 33 additions & 0 deletions src/CSnakes.Runtime.Tests/CSnakes.Runtime.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="python" Version="3.12.4" />
<PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
<PackageReference Include="MartinCostello.Logging.XUnit" Version="0.4.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CSnakes.Runtime\CSnakes.Runtime.csproj" />
</ItemGroup>

<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>

<ItemGroup>
<Folder Include="Python\" />
</ItemGroup>

</Project>
30 changes: 30 additions & 0 deletions src/CSnakes.Runtime.Tests/Converter/BoolConverterTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using CSnakes.Runtime.Python;
using System.ComponentModel;

namespace CSnakes.Runtime.Tests.Converter;

public class BoolConverterTest : ConverterTestBase
{
[Theory]
[InlineData(true)]
[InlineData(false)]
public void TestBoolBidirectional(bool input)
{
TypeConverter td = TypeDescriptor.GetConverter(typeof(PyObject));

Assert.True(td.CanConvertFrom(typeof(bool)));

using (GIL.Acquire())
{
using PyObject? pyObj = td.ConvertFrom(input) as PyObject;

Assert.NotNull(pyObj);

Assert.True(td.CanConvertTo(typeof(bool)));

// Convert back
object? str = td.ConvertTo(pyObj, typeof(bool));
Assert.Equal(input, str);
}
}
}
33 changes: 33 additions & 0 deletions src/CSnakes.Runtime.Tests/Converter/ConverterTestBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace CSnakes.Runtime.Tests.Converter;
public class ConverterTestBase : IDisposable
{
protected readonly IPythonEnvironment env;
protected readonly IHost app;

public ConverterTestBase()
{
app = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
var pb = services.WithPython();
pb.WithHome(Environment.CurrentDirectory);

pb.FromNuGet("3.12.4").FromMacOSInstallerLocator("3.12").FromEnvironmentVariable("Python3_ROOT_DIR", "3.12.4");

services.AddLogging(builder => builder.AddXUnit());
})
.Build();

env = app.Services.GetRequiredService<IPythonEnvironment>();
}

public void Dispose()
{
GC.SuppressFinalize(this);
GC.Collect();
}
}
28 changes: 28 additions & 0 deletions src/CSnakes.Runtime.Tests/Converter/DictionaryConverterTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using CSnakes.Runtime.Python;
using System.ComponentModel;

namespace CSnakes.Runtime.Tests.Converter;

public class DictionaryConverterTest : ConverterTestBase
{
[Fact]
public void DictionaryConverter()
{
Dictionary<string, string> input = new()
{
["Hello"] = "World?",
["Foo"] = "Bar"
};
TypeConverter td = TypeDescriptor.GetConverter(typeof(PyObject));
Assert.True(td.CanConvertFrom(input.GetType()));
using (GIL.Acquire())
{
using PyObject? pyObj = td.ConvertFrom(input) as PyObject;
Assert.NotNull(pyObj);
Assert.True(td.CanConvertTo(input.GetType()));
// Convert back
object? str = td.ConvertTo(pyObj, input.GetType());
Assert.Equal(input, str);
}
}
}
32 changes: 32 additions & 0 deletions src/CSnakes.Runtime.Tests/Converter/DoubleConverterTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using CSnakes.Runtime.Python;
using System.ComponentModel;

namespace CSnakes.Runtime.Tests.Converter;

public class DoubleConverterTest : ConverterTestBase
{
[Theory]
[InlineData(0.0)]
[InlineData(2.0)]
[InlineData(-2.0)]
[InlineData(double.NegativeInfinity)]
[InlineData(double.PositiveInfinity)]
public void TestDoubleBidirectional(double input)
{
var td = TypeDescriptor.GetConverter(typeof(PyObject));

Assert.True(td.CanConvertFrom(typeof(double)));
using (GIL.Acquire())
{
using PyObject? pyObj = td.ConvertFrom(input) as PyObject;

Assert.NotNull(pyObj);

Assert.True(td.CanConvertTo(typeof(double)));

// Convert back
object? str = td.ConvertTo(pyObj, typeof(double));
Assert.Equal(input, str);
}
}
}
51 changes: 51 additions & 0 deletions src/CSnakes.Runtime.Tests/Converter/ListConverterTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using CSnakes.Runtime.Python;
using System.ComponentModel;

namespace CSnakes.Runtime.Tests.Converter;

public class ListConverterTest : ConverterTestBase
{
[Fact]
public void IEnumerableConverter()
{
IEnumerable<string> input = ["Hell0", "W0rld"];

var td = TypeDescriptor.GetConverter(typeof(PyObject));

Assert.True(td.CanConvertFrom(input.GetType()));
using (GIL.Acquire())
{
using PyObject? pyObj = td.ConvertFrom(input) as PyObject;

Assert.NotNull(pyObj);

Assert.True(td.CanConvertTo(input.GetType()));

// Convert back
object? str = td.ConvertTo(pyObj, input.GetType());
Assert.Equal(input, str);
}
}

[Fact]
public void ListConverter()
{
List<long> input = [123456, 123562];

var td = TypeDescriptor.GetConverter(typeof(PyObject));

Assert.True(td.CanConvertFrom(input.GetType()));
using (GIL.Acquire())
{
using PyObject? pyObj = td.ConvertFrom(input) as PyObject;

Assert.NotNull(pyObj);

Assert.True(td.CanConvertTo(input.GetType()));

// Convert back
object? str = td.ConvertTo(pyObj, input.GetType());
Assert.Equal(input, str);
}
}
}
Loading
Loading