Skip to content

Commit fa8cd54

Browse files
committed
Add ., ./lib, ./plugin directories to path for Python plugins
1 parent 14f1a5a commit fa8cd54

File tree

2 files changed

+75
-8
lines changed

2 files changed

+75
-8
lines changed

Flow.Launcher.Core/Plugin/PythonPlugin.cs

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Diagnostics;
1+
using System;
2+
using System.Diagnostics;
23
using System.IO;
34
using System.Text.Json;
45
using System.Threading;
@@ -29,10 +30,6 @@ public PythonPlugin(string filename)
2930
_startInfo.EnvironmentVariables["FLOW_VERSION"] = Constant.Version;
3031
_startInfo.EnvironmentVariables["FLOW_PROGRAM_DIRECTORY"] = Constant.ProgramDirectory;
3132
_startInfo.EnvironmentVariables["FLOW_APPLICATION_DIRECTORY"] = Constant.ApplicationDirectory;
32-
33-
34-
//Add -B flag to tell python don't write .py[co] files. Because .pyc contains location infos which will prevent python portable
35-
_startInfo.ArgumentList.Add("-B");
3633
}
3734

3835
protected override Task<Stream> RequestAsync(JsonRPCRequestModel request, CancellationToken token = default)
@@ -50,10 +47,51 @@ protected override string Request(JsonRPCRequestModel rpcRequest, CancellationTo
5047
// TODO: Async Action
5148
return Execute(_startInfo);
5249
}
50+
5351
public override async Task InitAsync(PluginInitContext context)
5452
{
55-
_startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath);
56-
_startInfo.ArgumentList.Add("");
53+
// Run .py files via `-c <code>`
54+
if (context.CurrentPluginMetadata.ExecuteFilePath.EndsWith(".py", StringComparison.OrdinalIgnoreCase))
55+
{
56+
var rootDirectory = context.CurrentPluginMetadata.PluginDirectory;
57+
var libDirectory = Path.Combine(rootDirectory, "lib");
58+
var pluginDirectory = Path.Combine(rootDirectory, "plugin");
59+
60+
// This makes it easier for plugin authors to import their own modules.
61+
// They won't have to add `.`, `./lib`, or `./plugin` to their sys.path manually.
62+
// Instead of running the .py file directly, we pass the code we want to run as a CLI argument.
63+
// This code sets sys.path for the plugin author and then runs the .py file via runpy.
64+
_startInfo.ArgumentList.Add("-c");
65+
_startInfo.ArgumentList.Add(
66+
$"""
67+
import sys
68+
sys.path.append(r'{rootDirectory}')
69+
sys.path.append(r'{libDirectory}')
70+
sys.path.append(r'{pluginDirectory}')
71+
72+
import runpy
73+
runpy.run_path(r'{context.CurrentPluginMetadata.ExecuteFilePath}', None, '__main__')
74+
"""
75+
);
76+
// Plugins always expect the JSON data to be in the third argument
77+
// (we're always setting it as _startInfo.ArgumentList[2] = ...).
78+
_startInfo.ArgumentList.Add("");
79+
// Because plugins always expect the JSON data to be in the third argument, and specifying -c <code>
80+
// takes up two arguments, we have to move `-B` to the end.
81+
_startInfo.ArgumentList.Add("-B");
82+
}
83+
// Run .pyz files as is
84+
else
85+
{
86+
// -B flag is needed to tell python not to write .py[co] files.
87+
// Because .pyc contains location infos which will prevent python portable
88+
_startInfo.ArgumentList.Add("-B");
89+
_startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath);
90+
// Plugins always expect the JSON data to be in the third argument
91+
// (we're always setting it as _startInfo.ArgumentList[2] = ...).
92+
_startInfo.ArgumentList.Add("");
93+
}
94+
5795
await base.InitAsync(context);
5896
_startInfo.WorkingDirectory = context.CurrentPluginMetadata.PluginDirectory;
5997
}

Flow.Launcher.Core/Plugin/PythonPluginV2.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,36 @@ public PythonPluginV2(string filename)
3333

3434
public override async Task InitAsync(PluginInitContext context)
3535
{
36-
StartInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath);
36+
// Run .py files via `-c <code>`
37+
if (context.CurrentPluginMetadata.ExecuteFilePath.EndsWith(".py", StringComparison.OrdinalIgnoreCase))
38+
{
39+
var rootDirectory = context.CurrentPluginMetadata.PluginDirectory;
40+
var libDirectory = Path.Combine(rootDirectory, "lib");
41+
var pluginDirectory = Path.Combine(rootDirectory, "plugin");
42+
var filePath = context.CurrentPluginMetadata.ExecuteFilePath;
43+
44+
// This makes it easier for plugin authors to import their own modules.
45+
// They won't have to add `.`, `./lib`, or `./plugin` to their sys.path manually.
46+
// Instead of running the .py file directly, we pass the code we want to run as a CLI argument.
47+
// This code sets sys.path for the plugin author and then runs the .py file via runpy.
48+
StartInfo.ArgumentList.Add("-c");
49+
StartInfo.ArgumentList.Add(
50+
$"""
51+
import sys
52+
sys.path.append(r'{rootDirectory}')
53+
sys.path.append(r'{libDirectory}')
54+
sys.path.append(r'{pluginDirectory}')
55+
56+
import runpy
57+
runpy.run_path(r'{filePath}', None, '__main__')
58+
"""
59+
);
60+
}
61+
// Run .pyz files as is
62+
else
63+
{
64+
StartInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath);
65+
}
3766
await base.InitAsync(context);
3867
}
3968

0 commit comments

Comments
 (0)