Showing posts with label Python. Show all posts
Showing posts with label Python. Show all posts

Saturday, August 9, 2025

Azure Automation Runbooks and Azure Cosmos DB for MongoDB

I recently wanted to run a daily job on an Azure Cosmos DB for MongoDB. I thought Logic Apps would be a good fit, but surprisingly there is still a no connector that supports Azure Cosmos DB for MongoDB (currently only supports Azure Cosmos DB for NoSQL), and that's a bummer.

But there are of course other approaches we can take, like Azure Automation Runbooks. 

In this post, let's see how we can create an Azure Automation Python Runbook to query Azure Cosmos DB for MongoDB.

I have an Azure Automation account created and I have created a Python 3.10 Runbook. Now in order to connect to MongoDB, I am going to use pymongo package. 

First let's add the package to Automation Account. Note: For Python 3.10 packages, only .whl files targeting cp310 Linux OS are currently supported.

I am downloading the pymongo package to my local computer.

pip download pymongo `
    --platform manylinux2014_x86_64 `
    --only-binary=:all: `
    --python-version 3.10

Upon completion of above command, I can see 2 .whl files, pymongo and a dependency.

.whl files
Then I am uploading both these .whl files to Python packages under Automation Account.

Add Python packages

Now I can run some python code to query my Azure Cosmos DB for MongoDB.

from pymongo import MongoClient

MONGODB_CONNECTIONSTRING = "mongodb://..."
DATABASE_NAME = "<Database_Name>"
COLLECTION_NAME = "<Collection_Name>"

client = MongoClient(MONGODB_CONNECTIONSTRING, ssl=True)
db = client[DATABASE_NAME]
collection = db[COLLECTION_NAME]

documents = collection.find(
    {
        # query to filter documents
    })

documents = list(documents)

client.close()
# TODO: Work with documents

Hope this helps.

Happy Coding.

Regards,
Jaliya

Thursday, June 19, 2025

Running Python Code within .NET Projects

Back home now after what was meant to be a relaxing holiday - unfortunately, it took quite a turn with some unexpected hospital stays both overseas and after coming home.

Started catching up and there has been some mind blowing announcements in the world of Software Development with AI.

For ML and AI, I think we all agree that Python is the go to programming language. Might change in the future, but at least currently that's the main one.

I recently had a requirement where we want to use a functionality that is written on Python to be consumed by a .NET application. The way I thought is to expose a Python API (using Flask, FastAPI etc), but then there is going to be a lot of data (floats) travelling through HTTP. Since I didn't have any other option, started on that.

And then on Microsoft Build 2025, there was this cool session on Python Meets .NET with Anthony Shaw and Scott Hanselman. It's a new project called CSnakes, where we could use Python using .NET and most importantly that's not by emulating or simulating Python. It's embedding Python into .NET process. .NET and Python code shares the same threads and same memory etc.
CSnakes
Let's have a look at a basic working example.

Here I have a basic Python function in a file called hello_world.py.
def say_hello(name: str) -> str:
    return f"Hello {name}!"
I have now created a Console Application that targets .NET 9 and installed CSnakes.Runtime package.
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="CSnakes.Runtime" Version="1.0.34" />
  </ItemGroup>

</Project>
I am putting the hello_world.py inside the project and updating .csproj file to copy the .py to Output directory. And this is a very important step, this enables CSnakes to run the source generator over Python files.
<ItemGroup>
  <AdditionalFiles Include="hello_world.py">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </AdditionalFiles>
</ItemGroup>
And now updating the Program.cs as follows.
using CSnakes.Runtime;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

IHostBuilder builder = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        // Path to your Python modules
        var home = Path.Join(Environment.CurrentDirectory, ".")
        services
            .WithPython()
            .WithHome(home)
            .FromRedistributable()// Download Python 3.12 and store it locally
    });

IHost app = builder.Build();

IPythonEnvironment pythonEnvironment =  app.Services.GetRequiredService<IPythonEnvironment>();

// IMPORTANT: Source generated by CSnakes
IHelloWorld helloWorld = pythonEnvironment.HelloWorld();
string result = helloWorld.SayHello("John Doe");
Console.WriteLine(result)// Hello John Doe!
Output
If you are wondering how IHelloWorld comes into the picture, it was generated at compile time. 
Generated Source
While it's the recommended approach, you can still use CSnakes without source generator.

Now let's see how an example of how to use a Python file that uses packages. We can make use of Python pip install and  requirements.txt .

First I am adding a requirements.txt file and enable copying it to the output.
<ItemGroup>
<AdditionalFiles Include="requirements.txt">
   <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </AdditionalFiles>
</ItemGroup>
Here for the demo purposes I am adding a simple package stringcase.
stringcase
Now I am modifying the hello_world.py file as follows.
import stringcase

def say_hello(name: str) -> str:
    return f"Hello {stringcase.titlecase(name)}!"
Now I am updating Program.cs the as follows.
using CSnakes.Runtime;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

IHostBuilder builder = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        // Path to your Python modules
        var home = Path.Join(Environment.CurrentDirectory, ".");
        services
            .WithPython()
            .WithHome(home)
            .FromRedistributable() // Download Python 3.12 and store it locally
            .WithVirtualEnvironment(Path.Join(home".venv"))
            .WithPipInstaller()// Optional, Installs packages listed in requirements.txt on startup
    });

IHost app = builder.Build();

IPythonEnvironment pythonEnvironment =
    app.Services.GetRequiredService<IPythonEnvironment>();

// Source generated by CSnakes
IHelloWorld helloWorld = pythonEnvironment.HelloWorld();
string result = helloWorld.SayHello("JohnDoe");
Console.WriteLine(result)// Hello John Doe!
Output
This is pretty cool!

Watch the video:

Happy Coding.

Regards,
Jaliya