This repository has been archived by the owner on Jan 25, 2023. It is now read-only.
forked from pythonnet/pythonnet
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added configurable Python.Runtime.dll loader.
- Loading branch information
Showing
18 changed files
with
678 additions
and
2 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Weavers> | ||
<ModuleInit/> | ||
</Weavers> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System; | ||
|
||
using Python.Config; | ||
|
||
/// <summary> | ||
/// Used by the ModuleInit. All code inside the Initialize method is ran as soon as the assembly is loaded. | ||
/// </summary> | ||
public static class ModuleInitializer | ||
{ | ||
/// <summary> | ||
/// Initializes the module. | ||
/// </summary> | ||
public static void Initialize() | ||
{ | ||
PythonConfig.EnsureInitialized(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
using System.Reflection; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
|
||
// General Information about an assembly is controlled through the following | ||
// set of attributes. Change these attribute values to modify the information | ||
// associated with an assembly. | ||
[assembly: AssemblyTitle("config")] | ||
[assembly: AssemblyDescription("")] | ||
[assembly: AssemblyConfiguration("")] | ||
[assembly: AssemblyCompany("")] | ||
[assembly: AssemblyProduct("config")] | ||
[assembly: AssemblyCopyright("Copyright © 2016")] | ||
[assembly: AssemblyTrademark("")] | ||
[assembly: AssemblyCulture("")] | ||
|
||
// Setting ComVisible to false makes the types in this assembly not visible | ||
// to COM components. If you need to access a type in this assembly from | ||
// COM, set the ComVisible attribute to true on that type. | ||
[assembly: ComVisible(false)] | ||
|
||
// The following GUID is for the ID of the typelib if this project is exposed to COM | ||
[assembly: Guid("c4779672-f707-4778-b901-7c63548a3d6a")] | ||
|
||
// PythonVersion information for an assembly consists of the following four values: | ||
// | ||
// Major PythonVersion | ||
// Minor PythonVersion | ||
// Build Number | ||
// Revision | ||
// | ||
// You can specify all the values or you can default the Build and Revision Numbers | ||
// by using the '*' as shown below: | ||
// [assembly: AssemblyVersion("1.0.*")] | ||
[assembly: AssemblyVersion("1.0.0.0")] | ||
[assembly: AssemblyFileVersion("1.0.0.0")] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | ||
<PropertyGroup> | ||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
<ProjectGuid>{C4779672-F707-4778-B901-7C63548A3D6A}</ProjectGuid> | ||
<OutputType>Library</OutputType> | ||
<AppDesignerFolder>Properties</AppDesignerFolder> | ||
<RootNamespace>Python.Config</RootNamespace> | ||
<AssemblyName>Python.Config</AssemblyName> | ||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> | ||
<FileAlignment>512</FileAlignment> | ||
<NuGetPackageImportStamp> | ||
</NuGetPackageImportStamp> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||
<DebugSymbols>true</DebugSymbols> | ||
<DebugType>full</DebugType> | ||
<Optimize>false</Optimize> | ||
<OutputPath>bin\Debug\</OutputPath> | ||
<DefineConstants>DEBUG;TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||
<DebugType>pdbonly</DebugType> | ||
<Optimize>true</Optimize> | ||
<OutputPath>bin\Release\</OutputPath> | ||
<DefineConstants>TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Compile Include="ModuleInitializer.cs" /> | ||
<Compile Include="Properties\AssemblyInfo.cs" /> | ||
<Compile Include="PythonConfig.cs" /> | ||
<Compile Include="PythonConfigSection.cs" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<Reference Include="System" /> | ||
<Reference Include="System.Configuration" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<Content Include="FodyWeavers.xml" /> | ||
<EmbeddedResource Include="Python.Runtime-Py27-Win64.dll"> | ||
<LogicalName>Python.Runtime-Py27-Win64.dll</LogicalName> | ||
</EmbeddedResource> | ||
<EmbeddedResource Include="Python.Runtime-Py35-Win64.dll"> | ||
<LogicalName>Python.Runtime-Py35-Win64.dll</LogicalName> | ||
</EmbeddedResource> | ||
<EmbeddedResource Include="Python.Runtime-Py27-Linux64.dll"> | ||
<LogicalName>Python.Runtime-Py27-Linux64.dll</LogicalName> | ||
</EmbeddedResource> | ||
<EmbeddedResource Include="Python.Runtime-Py35-Linux64.dll"> | ||
<LogicalName>Python.Runtime-Py35-Linux64.dll</LogicalName> | ||
</EmbeddedResource> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="packages.config" /> | ||
</ItemGroup> | ||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||
<Import Project="..\..\packages\Fody.1.29.4\build\portable-net+sl+win+wpa+wp\Fody.targets" Condition="Exists('..\..\packages\Fody.1.29.4\build\portable-net+sl+win+wpa+wp\Fody.targets')" /> | ||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> | ||
<PropertyGroup> | ||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> | ||
</PropertyGroup> | ||
<Error Condition="!Exists('..\..\packages\Fody.1.29.4\build\portable-net+sl+win+wpa+wp\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Fody.1.29.4\build\portable-net+sl+win+wpa+wp\Fody.targets'))" /> | ||
</Target> | ||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | ||
Other similar extension points exist, see Microsoft.Common.targets. | ||
<Target Name="BeforeBuild"> | ||
</Target> | ||
<Target Name="AfterBuild"> | ||
</Target> | ||
--> | ||
</Project> |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
namespace Python.Config | ||
{ | ||
using System; | ||
using System.Configuration; | ||
using System.IO; | ||
using System.Reflection; | ||
using System.Text.RegularExpressions; | ||
|
||
/// <summary> | ||
/// Python.Net runtime configuration. | ||
/// </summary> | ||
public static class PythonConfig | ||
{ | ||
private static object _assemblyLoadLock = new object(); | ||
|
||
private static Exception _configException; | ||
|
||
private static Assembly _pythonRuntimeAssembly; | ||
|
||
private static string _pythonVersion; | ||
|
||
private static Regex _versionNumberRegex = new Regex("^(?<major>\\d)\\.(?<minor>\\d)$"); | ||
|
||
/// <summary> | ||
/// Initializes static members of the <see cref="PythonConfig"/> class. | ||
/// </summary> | ||
static PythonConfig() | ||
{ | ||
if (IntPtr.Size == 4) | ||
{ | ||
throw new NotSupportedException("32 bit platform not supported by Python.Config library."); | ||
} | ||
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolveHandler; | ||
} | ||
|
||
/// <summary> | ||
/// Loaded assembly name. | ||
/// </summary> | ||
public static string LoadedRuntimeAssembly { get; private set; } | ||
|
||
/// <summary> | ||
/// Pyhon runtime version. Can be changed only | ||
/// </summary> | ||
public static string PythonVersion | ||
{ | ||
get | ||
{ | ||
if (_pythonVersion == null) | ||
{ | ||
try | ||
{ | ||
var pythonConfigSection = (PythonConfigSection)ConfigurationManager.GetSection("pythonConfig"); | ||
_pythonVersion = pythonConfigSection.PythonVersion; | ||
|
||
ValidatePythonVersion(_pythonVersion); | ||
} | ||
catch (Exception ex) | ||
{ | ||
_pythonVersion = "2.7"; | ||
_configException = ex; | ||
AppDomain.CurrentDomain.SetData("PythonConfigException", _configException); | ||
} | ||
} | ||
|
||
return _pythonVersion; | ||
} | ||
|
||
private set | ||
{ | ||
// Disabling this feature. Dynamic version select should be implemented through callback in configuration file. | ||
if (IsRuntimeAssemblyLoaded) | ||
{ | ||
throw new InvalidOperationException( | ||
"Python version can be changed only before Python.Runtime assembly loaded by CLR."); | ||
} | ||
|
||
ValidatePythonVersion(value); | ||
_pythonVersion = value; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Used internally to determine that Python.Runtime assembly already loaded. | ||
/// </summary> | ||
internal static bool IsRuntimeAssemblyLoaded { get; set; } | ||
|
||
/// <summary> | ||
/// Forces Python Config library to be initialized. | ||
/// </summary> | ||
public static void EnsureInitialized() | ||
{ | ||
// Do nothing, but forces CLR to load PythonConfig type. | ||
} | ||
|
||
private static Assembly AssemblyResolveHandler(object sender, ResolveEventArgs args) | ||
{ | ||
if (args.Name.StartsWith("Python.Runtime")) | ||
{ | ||
lock (_assemblyLoadLock) | ||
{ | ||
if (_pythonRuntimeAssembly != null) | ||
{ | ||
return _pythonRuntimeAssembly; | ||
} | ||
|
||
string platform = Path.DirectorySeparatorChar == '\\' ? "Win64" : "Linux64"; | ||
|
||
// We will load assembly here. | ||
string resourceName = $"Python.Runtime-Py{PythonVersion.Replace(".", string.Empty)}-{platform}.dll"; | ||
|
||
// looks for the assembly from the resources and load it | ||
using (var stream = typeof(PythonConfig).Assembly.GetManifestResourceStream(resourceName)) | ||
{ | ||
if (stream != null) | ||
{ | ||
byte[] assemblyData = new byte[stream.Length]; | ||
stream.Read(assemblyData, 0, assemblyData.Length); | ||
try | ||
{ | ||
_pythonRuntimeAssembly = Assembly.Load(assemblyData); | ||
LoadedRuntimeAssembly = resourceName; | ||
return _pythonRuntimeAssembly; | ||
} | ||
catch (Exception ex) | ||
{ | ||
AppDomain.CurrentDomain.SetData("PythonConfigException", ex); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
private static void ValidatePythonVersion(string version) | ||
{ | ||
if (!_versionNumberRegex.Match(version).Success) | ||
{ | ||
throw new ArgumentException("Python version should be specified in x.y, for example \"2.7\"."); | ||
} | ||
|
||
if (version != "2.7" && version != "3.5") | ||
{ | ||
throw new ArgumentException("Unsupported python version. Only 2.7 and 3.5 are supported."); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
namespace Python.Config | ||
{ | ||
using System; | ||
using System.Configuration; | ||
|
||
public class PythonConfigSection : ConfigurationSection | ||
{ | ||
[ConfigurationProperty("pythonVersion", DefaultValue = "2.7", IsRequired = true)] | ||
public string PythonVersion | ||
{ | ||
get | ||
{ | ||
return (string)this["pythonVersion"]; | ||
} | ||
|
||
set | ||
{ | ||
this["pythonVersion"] = value; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<packages> | ||
<package id="Fody" version="1.29.4" targetFramework="net40" developmentDependency="true" /> | ||
<package id="ModuleInit.Fody" version="1.5.9.0" targetFramework="net40" developmentDependency="true" /> | ||
</packages> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<configuration> | ||
<configSections> | ||
<section name="pythonConfig" type="Python.Config.PythonConfigSection, Python.Config, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> | ||
</configSections> | ||
<pythonConfig pythonVersion="3.5"/> | ||
</configuration> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
namespace Python.Config.Test | ||
{ | ||
using System; | ||
|
||
using Python.Runtime; | ||
|
||
internal class Program | ||
{ | ||
static Program() | ||
{ | ||
Console.WriteLine("Starting application..."); | ||
// Required to be placed in the static constructor for Mono. | ||
PythonConfig.EnsureInitialized(); | ||
} | ||
|
||
[STAThread] | ||
private static int Main(string[] args) | ||
{ | ||
// Mono workaround required to fix AssemblyResolve + EntryPoint class bug. | ||
// Classes that was referenced from EntryPoint class cannot use assemblies resolved through "AssemblyResolve" | ||
Action monoWorkaround = () => | ||
{ | ||
try | ||
{ | ||
if (PythonConfig.LoadedRuntimeAssembly != null) | ||
{ | ||
Console.WriteLine( | ||
$"Python.runtime.dll substituted by {PythonConfig.LoadedRuntimeAssembly}."); | ||
} | ||
else | ||
{ | ||
Console.WriteLine( | ||
$"Python.runtime.dll was loaded from application directory."); | ||
} | ||
// You should put this initialized only if some component starting to use it before first application configuration file read attempt. | ||
// So in rare cases. | ||
PythonEngine.Initialize(); | ||
// Like that. | ||
try | ||
{ | ||
using (Py.GIL()) | ||
{ | ||
dynamic sysModule = Py.Import("sys"); | ||
Console.WriteLine("Python engine version:"); | ||
Console.WriteLine(sysModule.version); | ||
} | ||
} | ||
finally | ||
{ | ||
PythonEngine.Shutdown(); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
Console.WriteLine(ex); | ||
} | ||
}; | ||
monoWorkaround(); | ||
|
||
return 0; | ||
} | ||
} | ||
} |
Oops, something went wrong.