Repository navigation
Embedding the standard library
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.
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.
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 asre, are implemented in C# by IronPython, and an importer placed beforeBuiltinImporterwould load the zip's Python version instead, which doesn't work. - The resource name is the
LogicalNamegiven to theEmbeddedResourceitem. WithoutLogicalName, it's your project's root namespace followed by the file name. - Only
.pyfiles 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.Unixlibrary, which a single-file publish leaves next to the executable. SetIncludeNativeLibrariesForSelfExtracttotrueto bundle it into the single file. - The same approach works for your own Python modules: put them in another zip with its own importer.
Still looking for more? Browse the Discussions tab, where you can ask questions to the IronPython community.
π IronPython