Skip to content

Embedding the standard library

StΓ©phane Lozier edited this page Nov 6, 2026 · 1 revision

When you host IronPython in a .NET application, Python code can only import standard library modules (json, re, collections, ...) if the engine can find them.

Using the IronPython.StdLib package

Add the IronPython.StdLib package next to IronPython:

<ItemGroup>
  <PackageReference Include="IronPython" Version="3.4.2" />
  <PackageReference Include="IronPython.StdLib" Version="3.4.2" />
</ItemGroup>

The package copies the standard library to a lib folder in your output directory, and the engine automatically adds the lib folder next to your application to sys.path. To load modules from other folders, see Add the standard library to a .NET project.

Embedding it in your assembly

If you'd rather not ship a lib folder, for example with a single-file app (PublishSingleFile), you can embed the standard library in your assembly as a zip file and import from it with ResourceMetaPathImporter.

Zip the package's .py files at build time (about 2.5 MB) and embed the zip as a resource:

<ItemGroup>
  <PackageReference Include="IronPython" Version="3.4.2" />
  <!-- GeneratePathProperty gives $(PkgIronPython_StdLib); ExcludeAssets stops it from copying lib to the output -->
  <PackageReference Include="IronPython.StdLib" Version="3.4.2" GeneratePathProperty="true" ExcludeAssets="contentFiles" />
</ItemGroup>

<Target Name="EmbedPythonStdLib" AfterTargets="PrepareForBuild">
  <PropertyGroup>
    <PythonLibDir>$(IntermediateOutputPath)pythonlib\</PythonLibDir>
  </PropertyGroup>
  <ItemGroup>
    <PythonLibFile Include="$(PkgIronPython_StdLib)\content\lib\**\*.py" />
  </ItemGroup>
  <Copy SourceFiles="@(PythonLibFile)" DestinationFiles="@(PythonLibFile->'$(PythonLibDir)%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="true" />
  <ZipDirectory SourceDirectory="$(PythonLibDir)" DestinationFile="$(IntermediateOutputPath)lib.zip" Overwrite="true" />
  <ItemGroup>
    <EmbeddedResource Include="$(IntermediateOutputPath)lib.zip" LogicalName="lib.zip" />
  </ItemGroup>
</Target>

Then add an importer for the resource to sys.meta_path:

using System.Collections.Generic;
using IronPython.Hosting;
using IronPython.Modules;

var engine = Python.CreateEngine();
var metaPath = engine.GetSysModule().GetVariable<IList<object>>("meta_path");
metaPath.Add(new ResourceMetaPathImporter(typeof(Program).Assembly, "lib.zip"));

engine.Execute("import json; print(json.dumps({'embedded': True}))");

Things to know:

  • Append the importer to sys.meta_path (as above) rather than inserting it first. Some standard modules, such as re, are implemented in C# by IronPython, and an importer placed before BuiltinImporter would load the zip's Python version instead, which doesn't work.
  • The resource name is the LogicalName given to the EmbeddedResource item. Without LogicalName, it's your project's root namespace followed by the file name.
  • Only .py files are imported, and a module's __file__ is its path inside the zip, which doesn't exist on disk, so code that reads files next to a module won't find them. The few standard modules that need data files (lib2to3, ensurepip, venv, ...) won't work this way.
  • On Linux and macOS, IronPython needs the native libMono.Unix library, which a single-file publish leaves next to the executable. Set IncludeNativeLibrariesForSelfExtract to true to bundle it into the single file.
  • The same approach works for your own Python modules: put them in another zip with its own importer.

Clone this wiki locally