public static PySignature GetSignature(PyScope scope, string functionName) { var s = new PySignature(); PyObject fn = scope.Get(functionName); var inspect = Py.Import("inspect"); var signature = inspect.InvokeMethod("signature", fn); var parameters = signature.GetAttr("parameters"); var keys = parameters.InvokeMethod("keys"); var argumentNames = new List <string>(); foreach (var key in keys.OfType <PyObject>()) { var p = parameters[key]; var name = p.GetAttr("name").As <string>(); argumentNames.Add(name); } PyDict annotations = new PyDict(fn.GetAttr("__annotations__")); foreach (var argumentName in argumentNames) { Type type; if (annotations.HasKey(argumentName)) { var pyType = annotations.GetItem(argumentName); type = ToClrType(pyType); } else { type = typeof(object); } s.Arguments.Add(new PyArgument { Name = argumentName, Type = type }); } Type returnType; if (annotations.HasKey("return")) { var returnPyType = annotations.GetItem("return"); returnType = ToClrType(returnPyType); } else { returnType = typeof(object); } s.ReturnType = returnType; return(s); }
protected virtual void UpdateSignature() { if (this.Graph == null) // file path resolving only possible when module is attached to graph { return; } logger.LogInformation("UpdateSignature"); lock (gate) { PySignature signature = null; // when there is no script available var src = this.GetScript(); if (string.IsNullOrEmpty(src)) { // there are no arguments signature = new PySignature(); this.Script = null; SetParserError(null); } else { mainThread.RunSync(() => { using (PyScope ps = Py.CreateScope()) { PyObject script = PythonEngine.Compile(src, filename ?? "", mode); ps.Execute(script); signature = PySignature.GetSignature(ps, this.FunctionName); this.Script = script; } }); this.SetParserError(null); } try { this.signature = signature; // remove all argument pins that no longer exist var unusedPins = argumentPins.Where(pin => !signature.HasArgument(pin.Id)).ToArray(); foreach (var unusedPin in unusedPins) { unusedPin.DisconnectAll(); argumentPins.Remove(unusedPin); logger.LogInformation($"Removing input pin: {unusedPin.Id}"); inputs.Remove(unusedPin); } foreach (var arg in signature.Arguments) { var existingPin = argumentPins.FirstOrDefault(x => x.Id == arg.Name); if (existingPin == null) { var newPin = this.AddInputPin(arg.Name, PinDataTypeFactory.FromType(arg.Type), PropertyMode.Allow); argumentPins.Add(newPin); } else { // check type if (existingPin.DataType.UnderlyingType != arg.Type) { existingPin.ChangeType(PinDataTypeFactory.FromType(arg.Type)); } } } // get all pin ids which are not member of this dynamic pin collection var nonDynamicPinIds = this.inputs.Where(x => !argumentPins.Contains(x)).Select(x => x.ObjectId); // reorder module input pins var orderedArgumentPinObjectIds = signature.Arguments.Select(x => argumentPins.First(y => y.Id == x.Name).ObjectId); var newOrder = nonDynamicPinIds.Concat(orderedArgumentPinObjectIds).ToArray(); this.inputs.Reorder(newOrder); // analyse return type of script Type[] returnTypes; if (signature.ReturnType == null) { returnTypes = new Type[0]; } else if (TypeHelpers.IsTuple(signature.ReturnType)) { returnTypes = TypeHelpers.GetTupleTypes(signature.ReturnType); } else { returnTypes = new Type[] { signature.ReturnType }; } // remove pins that are not needed anymore while (resultPins.Count > returnTypes.Length) { var last = resultPins[resultPins.Count - 1]; logger.LogInformation($"Removing output pin: {last.Id}"); last.DisconnectAll(); outputs.Remove(last); resultPins.RemoveAt(resultPins.Count - 1); } for (int i = 0; i < returnTypes.Length; i++) { if (i < resultPins.Count) { var existingPin = resultPins[i]; if (existingPin.DataType.UnderlyingType != returnTypes[i]) { existingPin.ChangeType(PinDataTypeFactory.FromType(returnTypes[i])); } } else { var newPin = this.AddOutputPin($"output{i}", PinDataTypeFactory.FromType(returnTypes[i])); resultPins.Add(newPin); } } } catch (Exception e) { throw; } } }