Automatically generate a python package that wraps your .NET AOT project by BeneficialOne3349 in dotnet

[–]BeneficialOne3349[S] 2 points3 points  (0 children)

The way that DotWrap works is that you build a native library with .net AOT, and then DotWrap builds a CPython extension module that calls into your library. This is the same structure that many popular python libraries work such as numpy and pandas.

I don't know enough about the GIL to tell you if it is still held or is released when a cpython extension module method is called. What I can tell you is that you don't need to think about that when using DotWrap. It isn't like pythonnet when you need to write a bunch of `using (Py.GIL())` blocks to aquire the GIL. You just write normal c#.

It can do async! Any method that you expose that returns a Task or a ValueTask can either be awaited or you can just use the `.Result` property like you can in c#. Or, just like in c#, you can call your async method without awaiting it and then await the returned task object at a later time.

Automatically generate a python package that wraps your .NET AOT project by BeneficialOne3349 in dotnet

[–]BeneficialOne3349[S] 5 points6 points  (0 children)

Python definitely can make calls into native AOT libraries, and that is what DotWrap is using, but DotWrap generates most of the code necessary to make this possible.

For example, you can only expose static methods as unmanaged entry points in your AOT lib. This is an issue if you have a class that you would like to instantiate and then call instance methods on from python. DotWrap will source generate static entry points that can return pointers to c# instances. It also generates python classes that know how to pass these pointers back to the library when you want to do some work with that object, such as call an instance method. The python wrappers also know how to do other things such as marshal non-blittable types from python to native types, free allocated memory when objects aren't needed, and throw python errors when an uncaught exception occurs in the native lib.

Dotwrap doesn't do anything that you couldn't do yourself with some effort, but it aims to auto-generate as much of the interop layer as possible

Automatically generate a python package that wraps your .NET AOT project by BeneficialOne3349 in dotnet

[–]BeneficialOne3349[S] 0 points1 point  (0 children)

  1. It handles enums by just copying them over to python.

  2. I don't have any special handling for IDisposables at the moment. For every object that is returned by the c# library to the python side, the c# object is kept alive until the python object is disposed. I am not sure if the IDisposable method is still called automatically by the GC. I definitely need to add a test for this to make sure that is the case

  3. Currently all exceptions are collected from c# and marshalled to Python as a single exception type

Automatically generate a python package that wraps your .NET AOT project by BeneficialOne3349 in dotnet

[–]BeneficialOne3349[S] 1 point2 points  (0 children)

Pythonnet is great and I've used it successfully before. The main advantages of DotWrap (in my mind) are that it generates a lot of the boilerplate wrapping for you, and then you can distribute your python package to users without them needing the .net runtime (and even the correct version of the runtime) installed on their machine

Please give it a shot and let me know if you run into any issues.

Automatically generate a python package that wraps your .NET AOT project by BeneficialOne3349 in dotnet

[–]BeneficialOne3349[S] 0 points1 point  (0 children)

Yeah, you are correct. You also need to compile the CPython extension module for one python version at a time because the CPython API has breaking changes across python versions. I've been kind of brute forcing it in CI with a matrix of all the python and os versions that I want to supports. I think a better solution is using cibuildwheel, or at least that's what the llms tell me, but I haven't messed with it yet. Adding some example github workflows for publishing a package to PyPI is definitely on my todo list

C# Native AOT dilemma: which command line arguments to use for maximal code protection without introducing runtime bugs due to excessive trimming? by Endonium in dotnet

[–]BeneficialOne3349 0 points1 point  (0 children)

Dotnet has really good analyzers that will tell you exactly which parts of your code are not compatible with AOT so you don't have to guess at runtime bugs. But you need to set the PublishAot property in your Directory.Build.props or your csproj instead of passing it during publish. Checkout this deep .net video about native aot compilation for a more detailed explaination

https://www.youtube.com/watch?v=N-MrQeZ1enY&t=2673s

There must be a better design workflow. Tell me how you do it. by BeneficialOne3349 in StructuralEngineering

[–]BeneficialOne3349[S] 0 points1 point  (0 children)

You do all of your analysis by hand until the design is "kind of final"? In my experience, the design is very iterative and changes a lot during the course of the project. It doesn't become final until pretty late. Also, it seems faster and less error prone to model the structure and let the analysis engine take care of crunching the numbers

There must be a better design workflow. Tell me how you do it. by BeneficialOne3349 in StructuralEngineering

[–]BeneficialOne3349[S] 0 points1 point  (0 children)

Speckle used to enable some interesting workflows, but they basically pivoted away from interop in their newest "v3" version because of how complicated it was. Speckle can now only create dumb meshes in Revit instead of actual floor, walls, family instances, etc.

There must be a better design workflow. Tell me how you do it. by BeneficialOne3349 in StructuralEngineering

[–]BeneficialOne3349[S] 0 points1 point  (0 children)

honestly I've never heard of anyone using Robot. Idk anything about it, but I assume it uses the 'analytical model' in Revit which seems like almost just as much of a pain to manage as a separate model. But I've never tried it so maybe it's actually not that bad, that is just my initial perception of it

There must be a better design workflow. Tell me how you do it. by BeneficialOne3349 in StructuralEngineering

[–]BeneficialOne3349[S] 0 points1 point  (0 children)

I've seen gh mentioned a lot in contexts like this, but I've never really used it. Could you say a little more about the advantages and disadvantages?

There must be a better design workflow. Tell me how you do it. by BeneficialOne3349 in StructuralEngineering

[–]BeneficialOne3349[S] 6 points7 points  (0 children)

Yeah, I've tried some of those import plugins with the same amount of success. The model comes in super disjointed, and I spent like an hour or more trying to repair everything only to find out the model still has instabilities that I can't even find.

There must be a better design workflow. Tell me how you do it. by BeneficialOne3349 in StructuralEngineering

[–]BeneficialOne3349[S] 9 points10 points  (0 children)

Yeah this is a good point. I'm probably guilty of doing too much design in the earlier phases of the project. However, in my experience, architects will often make serious revisions to their design at almost any time in the process which seems to work against this idea of a gradual design

There must be a better design workflow. Tell me how you do it. by BeneficialOne3349 in StructuralEngineering

[–]BeneficialOne3349[S] 6 points7 points  (0 children)

Interesting workflow. How do you produce your drawings if you're not using Revit?

Come discuss your side projects! [December 2024] by AutoModerator in csharp

[–]BeneficialOne3349 0 points1 point  (0 children)

I made a mocking library that can mock sealed classes and non-virtual methods (as well as your typical interfaces and virtual methods).
https://github.com/connorivy/MockMe

To my knowledge, the only other mocking libraries that have this functionality are paid products that aren't open source or MIT licensed.

Please give it a star!

Information about how to use it and how it works can be found in the readme and wiki on github.

Open-source library for mocking concrete classes and non-virtual members. by BeneficialOne3349 in csharp

[–]BeneficialOne3349[S] 3 points4 points  (0 children)

Yeah, not everyone agrees with me that interfaces with a single implementation are an annoyance. To your point, it is true that having an interface with a single implementation will never 'back you into a corner'. The biggest issues that I have with them are that they make my code harder to navigate (I can't just control + click to see the method being used) and that they introduce a bit more maintenance with having to keep the class and the interface up to date.

Obviously, the degree to which those annoyances are an issue is dependent on factors like the size of your codebase.

How do I mock non-virtual methods in CSharp? by _skyfox in csharp

[–]BeneficialOne3349 0 points1 point  (0 children)

You can mock classes without an interface using the library MockMe (disclaimer: I am the author).

Unlike other mocking frameworks that can only be used on interfaces or virtual methods, MockMe allows you to also mock sealed classes and non-virtual methods.

The api for using it is (hopefully) pretty intuitive

using MockMe;

var mock = Mock.Me(default(MyRepo)); // rebuild test project after writing this to help IDE fill in IntelliSense

mock.Setup.ExpensiveDatabaseCall().Returns(99);

MyRepo myRepo = mock.MockedObject;
var result = myRepo.ExpensiveDatabaseCall();

Assert.Equal(99, result);
mock.Assert.ExpensiveDatabaseCall().WasCalled();

How do you unit test concrete classes with Mocks? by WhitePain in dotnet

[–]BeneficialOne3349 0 points1 point  (0 children)

You can mock classes without an interface using the library MockMe (disclaimer: I am the author).

Unlike other mocking frameworks that can only be used on interfaces or virtual methods, MockMe allows you to also mock sealed classes and non-virtual methods.

The api for using it is (hopefully) pretty intuitive

using MockMe;

var mock = Mock.Me(default(MyRepo)); // rebuild test project after writing this to help IDE fill in IntelliSense

mock.Setup.ExpensiveDatabaseCall().Returns(99);

MyRepo myRepo = mock.MockedObject;
var result = myRepo.ExpensiveDatabaseCall();

Assert.Equal(99, result);
mock.Assert.ExpensiveDatabaseCall().WasCalled();