Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python activities issues OSAC 39,40,41,50 #71

Merged
merged 17 commits into from
Nov 12, 2020
Merged
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
################################################################################
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
################################################################################

/.vs
Binary file modified Activities/Python/3rdparty/Python.Runtime.27.dll
Binary file not shown.
Binary file modified Activities/Python/3rdparty/Python.Runtime.35.dll
Binary file not shown.
Binary file modified Activities/Python/3rdparty/Python.Runtime.36.dll
Binary file not shown.
Binary file added Activities/Python/3rdparty/Python.Runtime.37.dll
Binary file not shown.
Binary file added Activities/Python/3rdparty/Python.Runtime.38.dll
Binary file not shown.
Binary file not shown.
Binary file modified Activities/Python/3rdparty/x64/Python.Runtime.35.dll
Binary file not shown.
Binary file modified Activities/Python/3rdparty/x64/Python.Runtime.36.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@
<comment>activity name</comment>
</data>
<data name="ScriptFileDescription" xml:space="preserve">
<value>Python script file</value>
<value>Full path to Python script file</value>
</data>
<data name="ScriptFileNameDisplayName" xml:space="preserve">
<value>File</value>
Expand Down
9 changes: 2 additions & 7 deletions Activities/Python/UiPath.Python.Activities/PythonScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ namespace UiPath.Python.Activities
[LocalizedDescription(nameof(Resources.PythonScopeDescription))]
public class PythonScope : AsyncTaskNativeActivity
{

[RequiredArgument]
[LocalizedCategory(nameof(Resources.Input))]
[LocalizedDisplayName(nameof(Resources.VersionNameDisplayName))]
[LocalizedDescription(nameof(Resources.VersionDescription))]
petcua1 marked this conversation as resolved.
Show resolved Hide resolved
[Browsable(false)]
[DefaultValue(Version.Auto)]
public Version Version { get; set; }

Expand Down Expand Up @@ -73,7 +69,6 @@ internal static IEngine GetPythonEngine(ActivityContext context)

public PythonScope()
{
Version = Version.Auto;
Body = new ActivityAction<object>
{
Argument = new DelegateInArgument<object>(PythonEngineSessionProperty),
Expand All @@ -94,7 +89,7 @@ protected override async Task<Action<NativeActivityContext>> ExecuteAsync(Native

cancellationToken.ThrowIfCancellationRequested();

_pythonEngine = EngineProvider.Get(Version, path, !Isolated, TargetPlatform, ShowConsole);
_pythonEngine = EngineProvider.Get(path, !Isolated, TargetPlatform, ShowConsole);

var workingFolder = WorkingFolder.Get(context);
if (!workingFolder.IsNullOrEmpty())
Expand Down
4 changes: 2 additions & 2 deletions Activities/Python/UiPath.Python.Host.Shared/PythonService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ public void Execute(string code)
}
}

public void Initialize(string path, Version version, string workingFolder)
public void Initialize(string path, string workingFolder)
{
try
{
_engine = EngineProvider.Get(version, path);
_engine = EngineProvider.Get(path);
_engine.Initialize(workingFolder, _ct).Wait();
}
catch (Exception ex)
Expand Down
53 changes: 46 additions & 7 deletions Activities/Python/UiPath.Python.Tests/Runtimes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,38 @@ public class Runtimes
{
new object[]
{
@"C:\Python\python-2.7.0-x86",
@"C:\Python\python27-x86",
Version.Python_27
},
new object[]
{
@"C:\Python\python-3.5.4-x86",
@"C:\Python\python33-x86",
Version.Python_33
},
new object[]
{
@"C:\Python\python34-x86",
Version.Python_34
},
new object[]
{
@"C:\Python\python35-x86",
Version.Python_35
},
new object[]
{
@"C:\Python\python-3.6.4-x86",
@"C:\Python\python36-x86",
Version.Python_36
},
new object[]
{
@"C:\Python\python37-x86",
Version.Python_37
},
new object[]
{
@"C:\Python\python38-x86",
Version.Python_38
}
};

Expand All @@ -96,13 +116,28 @@ public class Runtimes
{
new object[]
{
@"C:\Python\python-3.5.4-x64",
@"C:\Python\python27-x64",
Version.Python_27
},
new object[]
{
@"C:\Python\python35-x64",
Version.Python_35
},
new object[]
{
@"C:\Python\python-3.6.4-x64",
@"C:\Python\python36-x64",
Version.Python_36
},
new object[]
{
@"C:\Python\python37-x64",
Version.Python_37
},
new object[]
{
@"C:\Python\python38-x64",
Version.Python_38
}
};

Expand Down Expand Up @@ -164,7 +199,9 @@ public async Task Types_OutOfProcess(string path, Version version)
private async Task RunTypesTest(string path, Version version, bool inProcess, TargetPlatform target)
{
// init engine
var engine = EngineProvider.Get(version, path, inProcess, target, true);
var engine = EngineProvider.Get(path, inProcess, target, true);
Assert.Equal(engine.Version, version);

await engine.Initialize(null, _ct);
// load test script
var pyScript = await engine.LoadScript(_typeTestScript, _ct);
Expand All @@ -189,7 +226,9 @@ private async Task RunTypesTest(string path, Version version, bool inProcess, Ta

private async Task RunBasicTest(string path, Version version, bool inProcess, TargetPlatform target)
{
var engine = EngineProvider.Get(version, path, inProcess, target, true);
var engine = EngineProvider.Get(path, inProcess, target, true);
Assert.Equal(engine.Version, version);

await engine.Initialize(null, _ct);

await engine.Execute(_basicTestScript, _ct);
Expand Down
32 changes: 24 additions & 8 deletions Activities/Python/UiPath.Python/EngineProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ public static class EngineProvider
{
private const string PythonHomeEnv = "PYTHONHOME";
private const string PythonExe = "python.exe";
private const string PythonVersionArgument = "--version";

// engines cache
private static object _lock = new object();
private static Dictionary<Version, IEngine> _cache = new Dictionary<Version, IEngine>();

public static IEngine Get(Version version, string path, bool inProcess = true, TargetPlatform target = TargetPlatform.x86, bool visible = false)
public static IEngine Get(string path, bool inProcess = true, TargetPlatform target = TargetPlatform.x86, bool visible = false)
{
IEngine engine = null;
Version version;
lock (_lock)
{
if (string.IsNullOrEmpty(path))
Expand All @@ -31,13 +33,10 @@ public static IEngine Get(Version version, string path, bool inProcess = true, T
Trace.TraceInformation($"Found Pyhton path {path}");
}

Autodetect(path, out version);
if (!version.IsValid())
{
Autodetect(path, out version);
if (!version.IsValid())
{
throw new ArgumentException(Resources.DetectVersionException);
}
throw new ArgumentException(Resources.DetectVersionException);
}

// TODO: target&visible are meaningless when running in-process (at least now), maybe it should be split
Expand Down Expand Up @@ -66,9 +65,26 @@ private static void Autodetect(string path, out Version version)
{
throw new FileNotFoundException(Resources.PythonExeNotFoundException, pyExe);
}

version = FileVersionInfo.GetVersionInfo(pyExe).Get();
Process process = new Process();
process.StartInfo = new ProcessStartInfo()
{
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden,
FileName = pyExe,
Arguments = PythonVersionArgument,
RedirectStandardError = true,
RedirectStandardOutput = true
};
process.Start();
// Now read the value, parse to int and add 1 (from the original script)
string ver = process.StandardError.ReadToEnd();
if(string.IsNullOrEmpty(ver))
ver = process.StandardOutput.ReadToEnd();
process.WaitForExit();
version = ver.GetVersionFromStr();
Trace.TraceInformation($"Autodetected Python version {version}");
}

}
}
1 change: 1 addition & 0 deletions Activities/Python/UiPath.Python/IEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public enum TargetPlatform
/// </summary>
public interface IEngine : IDisposable
{
Version Version { get; }
#region Lifecycle
Task Initialize(string workingFolder, CancellationToken ct);

Expand Down
24 changes: 12 additions & 12 deletions Activities/Python/UiPath.Python/Impl/DynamicStaticTypeMembers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ private DynamicStaticTypeMembers(Type type)
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(this.type != null);
Contract.Invariant(type != null);
}

/// <summary>
Expand All @@ -58,12 +58,12 @@ public override bool TryGetMember(GetMemberBinder binder, out object result)
Contract.Assume(binder != null);
Contract.Assume(binder.Name != null);

Trace.TraceEvent(TraceEventType.Verbose, 0, "Getting the value of static property " + binder.Name + " on type " + this.type.Name);
Trace.TraceEvent(TraceEventType.Verbose, 0, "Getting the value of static property " + binder.Name + " on type " + type.Name);

var prop = this.type.GetProperty(binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public);
var prop = type.GetProperty(binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public);
if (prop == null)
{
Trace.TraceEvent(TraceEventType.Error, 0, "Could not find static property " + binder.Name + " on type " + this.type.Name);
Trace.TraceEvent(TraceEventType.Error, 0, "Could not find static property " + binder.Name + " on type " + type.Name);
result = null;
return false;
}
Expand All @@ -85,12 +85,12 @@ public override bool TrySetMember(SetMemberBinder binder, object value)
Contract.Assume(binder != null);
Contract.Assume(binder.Name != null);

Trace.TraceEvent(TraceEventType.Verbose, 0, "Setting the value of static property " + binder.Name + " on type " + this.type.Name);
Trace.TraceEvent(TraceEventType.Verbose, 0, "Setting the value of static property " + binder.Name + " on type " + type.Name);

var prop = this.type.GetProperty(binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public);
var prop = type.GetProperty(binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public);
if (prop == null)
{
Trace.TraceEvent(TraceEventType.Error, 0, "Could not find static property " + binder.Name + " on type " + this.type.Name);
Trace.TraceEvent(TraceEventType.Error, 0, "Could not find static property " + binder.Name + " on type " + type.Name);
return false;
}

Expand All @@ -113,7 +113,7 @@ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, o
Contract.Assume(binder.Name != null);
Contract.Assume(args != null);

Trace.TraceEvent(TraceEventType.Verbose, 0, "Invoking static method " + binder.Name + " on type " + this.type.Name + " with argument types { " + string.Join(", ", args.Select(x => x == null ? "<unknown>" : x.GetType().Name)) + " }");
Trace.TraceEvent(TraceEventType.Verbose, 0, "Invoking static method " + binder.Name + " on type " + type.Name + " with argument types { " + string.Join(", ", args.Select(x => x == null ? "<unknown>" : x.GetType().Name)) + " }");

// Convert any RefOutArg arguments into ref/out arguments
var refArguments = new RefOutArg[args.Length];
Expand All @@ -132,22 +132,22 @@ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, o
MethodBase method;
try
{
var methods = this.type.GetMethods(flags).Where(x => x.Name == binder.Name);
var methods = type.GetMethods(flags).Where(x => x.Name == binder.Name);
Contract.Assume(Type.DefaultBinder != null);
method = Type.DefaultBinder.BindToMethod(flags, methods.ToArray(), ref args, null, null, null, out state);
Contract.Assume(method != null);
Contract.Assume(args != null);
}
catch (Exception ex)
{
Trace.TraceEvent(TraceEventType.Error, 0, "Could not find static method " + binder.Name + " on type " + this.type.Name + ": [" + ex.GetType() + "] " + ex.Message);
Trace.TraceEvent(TraceEventType.Error, 0, "Could not find static method " + binder.Name + " on type " + type.Name + ": [" + ex.GetType() + "] " + ex.Message);
throw;
}

// Ensure that all ref/out arguments were properly wrapped
if (method.GetParameters().Count(x => x.ParameterType.IsByRef) != refArguments.Count(x => x != null))
{
throw new ArgumentException("ref/out parameters need a RefOutArg wrapper when invoking " + this.type.Name + "." + binder.Name + ".");
throw new ArgumentException("ref/out parameters need a RefOutArg wrapper when invoking " + type.Name + "." + binder.Name + ".");
}

// Invoke the method, allowing exceptions to propogate
Expand Down Expand Up @@ -206,7 +206,7 @@ public static dynamic Create<T>()
/// <returns>A <see cref="System.String"/> that represents this instance.</returns>
public override string ToString()
{
return this.type.Name;
return type.Name;
}
}
}
8 changes: 7 additions & 1 deletion Activities/Python/UiPath.Python/Impl/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ internal Engine(Version version, string path)
}

#region IEngine
public Version Version { get { return _version; } }
public async Task Initialize(string workingFolder, CancellationToken ct)
{
if (!_initialized)
Expand Down Expand Up @@ -89,7 +90,10 @@ public async Task Initialize(string workingFolder, CancellationToken ct)
ct.ThrowIfCancellationRequested();

_pyEngine.PythonHome = _path;
_pyEngine.Initialize(null, null);
if (_version == Version.Python_33 || _version == Version.Python_34)
_pyEngine.Initialize(null, null);
else
_pyEngine.Initialize(null, null, null);
ct.ThrowIfCancellationRequested();

_pythreads = _pyEngine.BeginAllowThreads();
Expand Down Expand Up @@ -247,6 +251,8 @@ public void Dispose()
#region script name caching
private Dictionary<string, string> _cachedModules = new Dictionary<string, string>();



/// <summary>
/// gets the module name based on the script content hash
/// </summary>
Expand Down
5 changes: 3 additions & 2 deletions Activities/Python/UiPath.Python/Impl/OutOfProcessEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal class OutOfProcessEngine : IEngine

#region Runtime info
private Version _version;
private string _path;
private string _path;
#endregion

internal OutOfProcessEngine(Version version, string path, TargetPlatform target, bool visible )
Expand All @@ -32,6 +32,7 @@ internal OutOfProcessEngine(Version version, string path, TargetPlatform target,
}

#region IEngine
public Version Version { get { return _version; } }
public Task Initialize(string workingFolder, CancellationToken ct)
{
ct.ThrowIfCancellationRequested();
Expand All @@ -48,7 +49,7 @@ public Task Initialize(string workingFolder, CancellationToken ct)
};
_provider.Create();
_proxy = new PythonProxy(_provider.Endpoint);
_proxy.Initialize(_path, _version, workingFolder);
_proxy.Initialize(_path, workingFolder);

sw.Stop();

Expand Down
Loading