Skip to content

Commit a981ec8

Browse files
committed
version 0.0.1
0 parents  commit a981ec8

File tree

12 files changed

+574
-0
lines changed

12 files changed

+574
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
build
2+
obj

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
## 0.0.1
2+
- Initial release.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 eseunghwan
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

PythonShell.NET.sln

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.0.31903.59
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PythonShell.NET", "Source\PythonShell.NET.csproj", "{CB35620C-709D-4532-B4E6-BB1FD37EC6F0}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PythonShell.NET.Tests", "Tests\PythonShell.NET.Tests.csproj", "{4A94A162-B69E-4076-AD96-8DF92AF715AA}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
Release|Any CPU = Release|Any CPU
14+
EndGlobalSection
15+
GlobalSection(SolutionProperties) = preSolution
16+
HideSolutionNode = FALSE
17+
EndGlobalSection
18+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
19+
{CB35620C-709D-4532-B4E6-BB1FD37EC6F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20+
{CB35620C-709D-4532-B4E6-BB1FD37EC6F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
21+
{CB35620C-709D-4532-B4E6-BB1FD37EC6F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
22+
{CB35620C-709D-4532-B4E6-BB1FD37EC6F0}.Release|Any CPU.Build.0 = Release|Any CPU
23+
{4A94A162-B69E-4076-AD96-8DF92AF715AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24+
{4A94A162-B69E-4076-AD96-8DF92AF715AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
25+
{4A94A162-B69E-4076-AD96-8DF92AF715AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
26+
{4A94A162-B69E-4076-AD96-8DF92AF715AA}.Release|Any CPU.Build.0 = Release|Any CPU
27+
EndGlobalSection
28+
EndGlobal

README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<h1 align="center">
2+
<br />
3+
PythonShell.NET
4+
</h1>
5+
<h3 align="center">
6+
Python Environment Manager and Executor for .NET
7+
<br />
8+
<br />
9+
</h3>
10+
<br />
11+
12+
Available for:
13+
- net5.0, net6.0
14+
15+
16+
Supported Platforms:
17+
- Windows 10+ (x86, amd64, arm64)
18+
- Linux Distos (amd64, arm64)
19+
- OSX 11+ (amd64, arm64)
20+
21+
<br />
22+
<hr>
23+
<br />
24+
<br />
25+
26+
# Install
27+
nuget package is not available not
28+
29+
<br /><br />
30+
31+
# Usage
32+
- basic usage
33+
```c#
34+
using PythonShell;
35+
using PythonShell.Listener;
36+
37+
var shell = PythonShell();
38+
await shell.Initialize();
39+
40+
shell.RunString("{pythonCode}");
41+
```
42+
43+
<br />
44+
45+
- onMessage, onError, onComplete
46+
```c#
47+
// setups like above ...
48+
shell.RunString(
49+
"{pythonCode}",
50+
listener: ShellListener {
51+
OnMessage = (message) {
52+
// if `echo` is `true`, log to console automatically
53+
Console.WriteLine("message!");
54+
},
55+
OnError = (e, s) {
56+
Console.WriteLine("error!");
57+
},
58+
OnComplete = () {
59+
Console.WriteLine("complete!");
60+
}
61+
}
62+
);
63+
```
64+
65+
<br />
66+
67+
for further informations, refers to [Shell.cs](https://github.com/eseunghwan/PythonShell.NET/blob/master/Source/src/Shell.cs)

Source/PythonShell.NET.csproj

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>net5.0;net6.0</TargetFrameworks>
5+
<Nullable>enable</Nullable>
6+
7+
<AssemblyName>PythonShell</AssemblyName>
8+
<OutputPath>build</OutputPath>
9+
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
10+
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
11+
</PropertyGroup>
12+
13+
<PropertyGroup>
14+
<PackageId>PythonShell.NET</PackageId>
15+
<Version>0.0.1</Version>
16+
<Authors>eseunghwan</Authors>
17+
<Company>Integrated.Design.Division</Company>
18+
</PropertyGroup>
19+
20+
</Project>

Source/src/Listener.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
using System;
3+
using System.Diagnostics;
4+
5+
6+
namespace PythonShell.Listener {
7+
public class ShellListener {
8+
public Action<String>? OnMessage { get; set; } = (message) => {};
9+
public Action<DataReceivedEventArgs>? OnError { get; set; } = (message) => {};
10+
public Action? OnComplete { get; set; } = () => {};
11+
}
12+
}

Source/src/Shell.cs

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
2+
using System;
3+
using System.IO;
4+
using System.Threading.Tasks;
5+
using System.Diagnostics;
6+
using System.Collections.Generic;
7+
using System.Runtime.InteropServices;
8+
9+
10+
namespace PythonShell {
11+
public class ShellConfig {
12+
public String DefaultPythonPath { get; set; } = "python3";
13+
public String DefaultPythonVersion { get; set; } = "3.9.13";
14+
public String? DefaultWorkingDirectory { get; set; } = null;
15+
public String? PythonRequireFile { get; set; } = null;
16+
public String[]? PythonRequires { get; set; } = null;
17+
18+
internal String? AppDir { get; set; } = null;
19+
internal String TempDir {
20+
get => Path.Join(AppDir, "temp");
21+
}
22+
internal String InstanceDir {
23+
get => Path.Join(AppDir, "instances");
24+
}
25+
internal String? DefaultPythonEnvPath { get; set; } = null;
26+
27+
public ShellConfig() {
28+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
29+
if (this.DefaultPythonPath == "python" || this.DefaultPythonPath == "python2" || this.DefaultPythonPath == "python3") {
30+
this.DefaultPythonPath = $"/usr/bin/{this.DefaultPythonPath}";
31+
}
32+
else if (!File.Exists(this.DefaultPythonPath)) {
33+
this.DefaultPythonPath = "/usr/bin/python3";
34+
}
35+
}
36+
37+
if (this.DefaultWorkingDirectory != null) {
38+
this.DefaultWorkingDirectory = Path.GetFullPath(this.DefaultWorkingDirectory);
39+
}
40+
}
41+
}
42+
43+
public class Shell {
44+
private List<Int32> RunningProccese { get; set; } = new List<Int32>();
45+
46+
public Boolean CreateDefaultEnv { get; set; } = false;
47+
public ShellConfig Config { get; set; } = new ShellConfig();
48+
public Boolean Resolved {
49+
get => this.RunningProccese.Count == 0;
50+
}
51+
52+
public async Task Initialize() {
53+
await Utils.Util.InitializeApp(this.Config, this.CreateDefaultEnv);
54+
}
55+
56+
public void Clear() {
57+
foreach (var path in Directory.GetDirectories(this.Config.InstanceDir)) {
58+
if (Path.GetFileName(path).ToLower() != "default") {
59+
Console.WriteLine(path);
60+
// Directory.Delete(path, true);
61+
}
62+
}
63+
}
64+
65+
public async Task<Process?> RunFile(String pythonFile, String? workingDirectory = null, Boolean useInstance = false, String? instanceName = null, Boolean echo = true, Listener.ShellListener? listener = null) {
66+
String pythonToRun;
67+
String instanceDir = "";
68+
if (useInstance) {
69+
var instanceMap = instanceName == null ? Utils.Util.CreateShellInstance(this.Config, instanceName) : Utils.Util.GetShellInstance(this.Config, instanceName);
70+
pythonToRun = instanceMap.Python;
71+
instanceDir = instanceMap.Dir;
72+
}
73+
else {
74+
pythonToRun = this.Config.DefaultPythonEnvPath ?? this.Config.DefaultPythonPath;
75+
}
76+
77+
var process = new Process {
78+
StartInfo = new ProcessStartInfo {
79+
FileName = pythonToRun,
80+
ArgumentList = { "-u", Path.GetFullPath(pythonFile) },
81+
WorkingDirectory = this.Config.DefaultWorkingDirectory ?? workingDirectory!,
82+
UseShellExecute = true, WindowStyle = ProcessWindowStyle.Hidden
83+
}
84+
}!;
85+
Int32 processId = Int32.MaxValue;
86+
87+
process.OutputDataReceived += (s, e) => {
88+
if (echo) {
89+
Console.WriteLine(e.Data);
90+
}
91+
92+
listener!.OnMessage!(e.Data!);
93+
};
94+
process.ErrorDataReceived += (s, e) => {
95+
this.RunningProccese.Remove(processId);
96+
if (useInstance) {
97+
Directory.Delete(instanceDir, true);
98+
}
99+
100+
listener!.OnError!(e);
101+
};
102+
process.Exited += (s, e) => {
103+
this.RunningProccese.Remove(processId);
104+
if (useInstance) {
105+
Directory.Delete(instanceDir, true);
106+
}
107+
108+
listener!.OnComplete!();
109+
};
110+
process.Start();
111+
processId = process.Id;
112+
this.RunningProccese.Add(processId);
113+
await process.WaitForExitAsync();
114+
115+
return process;
116+
}
117+
118+
public async Task<Process?> RunString(String pythonCode, String? workingDirectory = null, Boolean useInstance = false, String? instanceName = null, Boolean echo = true, Listener.ShellListener? listener = null) {
119+
String tempPythonFileName = DateTime.Now.ToString("yyyy.MM.dd.HH.mm.ss");
120+
String tempPythonFile;
121+
if (useInstance) {
122+
var instanceMap = instanceName == null ? Utils.Util.CreateShellInstance(this.Config, instanceName) : Utils.Util.GetShellInstance(this.Config, instanceName);
123+
tempPythonFile = Path.Join(instanceMap.Dir, "temp", tempPythonFileName);
124+
}
125+
else {
126+
tempPythonFile = Path.Join(this.Config.TempDir, tempPythonFileName);
127+
}
128+
File.WriteAllText(tempPythonFile, pythonCode, System.Text.Encoding.UTF8);
129+
130+
var newListener = new Listener.ShellListener {
131+
OnMessage = listener!.OnMessage,
132+
OnError = (e) => {
133+
listener!.OnError!(e);
134+
if (File.Exists(tempPythonFile)) {
135+
File.Delete(tempPythonFile);
136+
}
137+
},
138+
OnComplete = () => {
139+
listener!.OnComplete!();
140+
if (File.Exists(tempPythonFile)) {
141+
File.Delete(tempPythonFile);
142+
}
143+
}
144+
};
145+
146+
return await this.RunFile(
147+
tempPythonFile, workingDirectory, useInstance, instanceName, echo, newListener
148+
);
149+
}
150+
}
151+
}

0 commit comments

Comments
 (0)