Exemple #1
0
        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;
                }
            }
        }