PyExpression 1.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package PyExpression --version 1.1.0
                    
NuGet\Install-Package PyExpression -Version 1.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PyExpression" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PyExpression" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="PyExpression" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PyExpression --version 1.1.0
                    
#r "nuget: PyExpression, 1.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PyExpression@1.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PyExpression&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=PyExpression&version=1.1.0
                    
Install as a Cake Tool

PyExpression

PyExpression is a small, controlled, Python-like expression and mini-script engine for C#.

It is designed for sandboxed execution with a deliberately limited language surface:

  • no Python runtime embedding
  • no IronPython
  • no Roslyn scripting
  • no arbitrary .NET object access
  • no file, network, system, or reflection access from scripts

The repository contains three main projects:

  • PyExpression - core class library
  • PyExpressionSandbox - WPF test application
  • PyExpression.Tests - xUnit test project

An example plugin project is also included:

  • PyFilter.Methods - sample provider assembly

What PyExpression Is

PyExpression parses a small Python-like language with its own lexer, parser, AST, and interpreter. It is intentionally smaller than Python and focuses on predictable behavior, explicit control over the callable surface, and easy extension.

Supported language features

  • literals:
    • integers
    • doubles
    • booleans
    • strings
  • expressions:
    • +, -, *, /, %
    • ==, !=, <, <=, >, >=
    • and, or, not
  • statements:
    • assignment
    • return
    • if / else
    • while
    • for ... in range(...)
    • break
    • continue
    • yield
    • yield from
  • collections:
    • list literals
    • dictionary literals
    • index access and indexed assignment
  • built-in functions:
    • abs
    • min
    • max
    • sum
    • sorted
    • keys
    • values
    • round
    • floor
    • ceil
    • pow
    • sqrt
    • len
    • clamp

Explicitly unsupported

  • import
  • class definitions
  • function definitions inside the script
  • arbitrary reflection
  • file system access
  • network access
  • system access
  • dynamic assembly execution
  • access to arbitrary .NET objects

Quick Start

Execute a script

using PyExpression;

var result = PyExpression.PyExpression.Execute(
    """
    x = n * 2
    return x
    """,
    new PyVar("n", 9));

Console.WriteLine(result.Value); // 18

Use the instance API

using PyExpression;

var expression = new PyExpression.PyExpression("""
    if n > 10:
        return 100
    else:
        return 50
    """)
{
    Vars = new[]
    {
        new PyVar("n", 11)
    }
};

var result = expression.Execute();
Console.WriteLine(result.Value); // 100

Async and streaming execution

using PyExpression;

var expression = new PyExpression.PyExpression("""
    i = 0
    while i < 3:
        i = i + 1
        yield i
    """);

await foreach (var item in expression.StreamAsync())
{
    Console.WriteLine(item);
}

Architecture

The interpreter is split into clear layers:

flowchart LR
    Script[Script Text] --> Lexer[Lexer / Tokenizer]
    Lexer --> Parser[Parser]
    Parser --> AST[AST]
    AST --> Interpreter[Interpreter]
    Vars[PyVar Collection] --> Context[ExecutionContext]
    Lib[PyLib + Providers] --> Interpreter
    Context --> Interpreter
    Interpreter --> Result[PyVar Result]
    Interpreter --> Stream[Yield Stream]

Internal components

  • Lexer converts the source text into tokens
  • Parser turns tokens into an AST
  • Interpreter evaluates statements and expressions
  • ExecutionContext stores variables and local scope
  • PyLib exposes the approved callable methods
  • PyVar holds typed input/output values

Public API Overview

PyExpression

Main class used to execute a script.

var expression = new PyExpression.PyExpression("return n * 2")
{
    Vars = new[] { new PyVar("n", 9) }
};

PyVar result = expression.Execute();

Useful members:

  • string Script
  • ICollection<PyVar> Vars
  • PyLib Library
  • int MaxIterations
  • PyVar Execute()
  • Task<PyVar> ExecuteAsync(...)
  • IAsyncEnumerable<object?> StreamAsync(...)
  • bool ContainsYield()
  • static PyVar Execute(string script, params PyVar[] vars)

PyVar

Represents a named value passed to or returned from the engine.

var value = new PyVar("n", 9);

PyLib

Registry of permitted methods and plugin providers.

var library = new PyLib();
library.Register(new MathMethods());

Useful members:

  • Register(string name, int minArgs, int? maxArgs, Func<IReadOnlyList<object?>, object?> handler)
  • Register(IPyMethods methods)
  • Register(Assembly assembly)
  • RegisterDirectory(string directoryPath)
  • LoadPluginsFromFolder(string directoryPath)
  • MethodNames
  • Providers
  • Manifests
  • Default

IPyMethods

Contract for providers that register methods into PyLib.

public sealed class MyMethods : PyMethods
{
    public override IPyPluginManifest Manifest => new PyPluginManifest(
        "MyMethods",
        new Version(1, 0, 0),
        "Custom helper methods");

    public override void Register(PyLib library)
    {
        library.Register("hello", 0, 0, _ => "world");
    }
}

IPyPluginManifest

Metadata contract used for plugin discovery and reporting.

public sealed record PyPluginManifest(
    string Name,
    Version Version,
    string Description) : IPyPluginManifest;

Default Methods

The built-in default provider is MathMethods.

It is always registered in PyLib.Default and provides the standard helper set:

  • arithmetic helpers
  • math functions
  • collection helpers

Example:

var result = PyExpression.PyExpression.Execute("return clamp(n * 3, 0, 100)", new PyVar("n", 7));
Console.WriteLine(result.Value); // 21

Sandbox

PyExpressionSandbox is a WPF demo application for live testing.

It includes:

  • typed variable editor
  • script editor
  • sync / async mode selection
  • output view
  • yield stream view
  • cancel button for async execution
  • generated C# snippet preview
  • copy button for the snippet

The sandbox is intended for interactive experimentation, not for production use.

Plugin Support

Plugins are controlled method provider assemblies that implement IPyMethods.

The platform supports:

  • direct registration of a provider instance
  • assembly scanning
  • folder-based plugin loading
var library = new PyLib();
library.Register(new PyFilter.Methods.PyFilterMethods());
library.Register(typeof(PyFilter.Methods.PyFilterMethods).Assembly);
var results = library.LoadPluginsFromFolder(@"C:\plugins");

Plugin metadata is separated through IPyPluginManifest.

flowchart TD
    DLL[Plugin DLL] --> Scan[Assembly Scan]
    Scan --> Provider[IPyMethods]
    Provider --> Manifest[IPyPluginManifest]
    Provider --> Register[PyLib Register]
    Register --> Methods[Allowed Methods]
    Manifest --> Result[PluginLoadResult]

Error Handling

The engine uses explicit exception types so callers can distinguish between:

  • parse errors
  • runtime errors
  • unknown variables
  • unknown methods
  • invalid argument counts
  • iteration limit violations

Examples:

try
{
    var result = PyExpression.PyExpression.Execute("return missing");
}
catch (PyUnknownVariableException ex)
{
    Console.WriteLine(ex.Message);
}

Examples

Variables

n = 5
x = n * 2
return x

Conditions

if n > 10:
    return 100
else:
    return 50

While loop

i = 0
sum = 0
while i < 5:
    sum = sum + i
    i = i + 1
return sum

For loop

sum = 0
for i in range(1, 6, 2):
    sum = sum + i
return sum

Yield stream

i = 0
while i < 3:
    i = i + 1
    yield i

Test Coverage

The xUnit test project covers:

  • variable access and overwriting
  • arithmetic and precedence
  • comparisons and boolean logic
  • conditions
  • loops
  • break / continue
  • collections and indexing
  • built-in methods
  • plugin loading
  • async execution
  • generator streaming
  • error cases

Repository Layout

PyExpressionSandbox/
  PyExpression/
  PyExpressionSandbox/
  PyExpression.Tests/
  PyFilter.Methods/
  README.md
  how-to-create-a-plugin.md

Building and Testing

dotnet build PyExpression\PyExpression.csproj -nologo
dotnet build PyFilter.Methods\PyFilter.Methods.csproj -nologo
dotnet build PyExpressionSandbox\PyExpressionSandbox.csproj -nologo
dotnet test PyExpression.tests\PyExpression.tests.csproj --no-build --no-restore -nologo

Next Steps

Good future extensions would be:

  • dictionaries with richer helpers
  • list and dictionary comprehensions
  • break / continue diagnostics in the sandbox UI
  • plugin manifest discovery from custom attributes
  • plugin manifest files or package metadata
  • more built-in collection helpers

Documentation

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.1 126 4/13/2026
1.1.0 107 4/13/2026