diff --git a/.github/scripts/check_file_version.ps1 b/.github/scripts/check_file_version.ps1 index a9c8a313824..816a480c007 100644 --- a/.github/scripts/check_file_version.ps1 +++ b/.github/scripts/check_file_version.ps1 @@ -68,7 +68,12 @@ $excludedFiles = @( "TuneUp.dll", "TuneUp.resources.dll", "Units.dll", - "Webview2Loader.dll" + "Webview2Loader.dll", + "DSPythonNet3.dll", + "DSPythonNet3.resources.dll", + "DSPythonNet3Extension.dll", + "DSPythonNet3Empty.dll", + "DSPythonNet3Wheels.dll" ) $noVersion = @() $wrongVersion = @() diff --git a/doc/distrib/Samples/en-US/Core/Core_Math.dyn b/doc/distrib/Samples/en-US/Core/Core_Math.dyn index c76ac7f8529..a0a4005d8bb 100644 --- a/doc/distrib/Samples/en-US/Core/Core_Math.dyn +++ b/doc/distrib/Samples/en-US/Core/Core_Math.dyn @@ -2015,7 +2015,7 @@ { "ConcreteType": "PythonNodeModels.PythonNode, PythonNodeModels", "Code": "import clr\r\nclr.AddReference('ProtoGeometry')\r\nfrom Autodesk.DesignScript.Geometry import *\r\n\r\nimport math\r\n\r\n# The inputs to this node will be stored as a list in the IN variable.\r\namp = IN[0] # single value\r\nx = IN[1] # list\r\ny = IN[2] # list (expect same length as x)\r\nc = IN[3] # single value\r\n\r\n# Declare an empty array of z-values\r\nz = []\r\n\r\n# Solve the equation for each x and y value\r\nfor index in range(len(x)):\r\n\tsum = math.pow(x[index],2) + math.pow(y[index],2) + math.pow(c,2)\r\n\tnum1 = math.sqrt(sum)\r\n\tnum2 = math.sin(num1)\r\n\tzVal = amp * num2 / num1\r\n\t\r\n\t# Append the answer to the list of z values\r\n\tz.append(zVal)\r\n\r\n# Assign the z-values to the OUT variable\r\nOUT = z", - "Engine": "CPython3", + "Engine": "PythonNet3", "VariableInputPorts": true, "Id": "7024be7096c74f46a832ce5749bba59a", "NodeType": "PythonScriptNode", diff --git a/doc/distrib/Samples/en-US/Core/Core_Python.dyn b/doc/distrib/Samples/en-US/Core/Core_Python.dyn index 53e7d1ca6a3..25f8f970260 100644 --- a/doc/distrib/Samples/en-US/Core/Core_Python.dyn +++ b/doc/distrib/Samples/en-US/Core/Core_Python.dyn @@ -12,7 +12,7 @@ { "ConcreteType": "PythonNodeModels.PythonNode, PythonNodeModels", "Code": "# Python script to find add or subtract a series of numbers. \r\n\r\n# Boiler-plate import statments included out-of-the-box\r\nimport clr\r\nclr.AddReference('ProtoGeometry')\r\nfrom Autodesk.DesignScript.Geometry import *\r\n\r\n# The inputs to this node will be stored as a list in the IN variable.\r\nsign = IN[0] # -1 for subtract all, 0 for do nothing, 1 for add all\r\nnums = IN[1] # List of numbers to subtract or add\r\n\r\npartials = [] # Empty array to contain partial sums or differences\r\nresult = 0 # Initialize the sum or difference to 0\r\n\r\n# Loop through each item and add it or subtract it from the result.\r\nfor index in range(len(nums)):\r\n\tif sign > 0:\r\n\t\tresult = result + nums[index]\r\n\t\tpartials.append(result)\r\n\telif sign == 0:\r\n\t\tpartials.append(result)\r\n\t\tcontinue\r\n\telse:\r\n\t\tresult = result - nums[index]\r\n\t\tpartials.append(result)\r\n\r\n# Assign the output to the OUT variable\r\n#OUT = results # Use this to output only the result.\r\nOUT = []\r\nOUT.append(result)\r\nOUT.append(partials)", - "Engine": "CPython3", + "Engine": "PythonNet3", "VariableInputPorts": true, "Id": "7183a2fe9a6a4eebb2233525a80ab2f2", "NodeType": "PythonScriptNode", @@ -82,8 +82,8 @@ "Outputs": [ { "Id": "30ec0136279d47edacf06a1f0ae3d56a", - "Name": "", - "Description": "Value of expression at line 1", + "Name": "range", + "Description": "0..10", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, @@ -203,8 +203,8 @@ "Outputs": [ { "Id": "08a98db6988e4ae3943f8c84d4ee8bd2", - "Name": "", - "Description": "Value of expression at line 1", + "Name": "integer", + "Description": "0", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, @@ -262,8 +262,8 @@ "Outputs": [ { "Id": "e74a6d9e041f45498775d1e07a81e84b", - "Name": "", - "Description": "Value of expression at line 1", + "Name": "integer", + "Description": "1", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, @@ -277,7 +277,7 @@ { "ConcreteType": "CoreNodeModels.Watch, CoreNodeModels", "WatchWidth": 35.0, - "WatchHeight": 38.0, + "WatchHeight": 40.0, "Id": "c44ca1114bbf48cc9b358b339af6c19e", "NodeType": "ExtensionNode", "Inputs": [ @@ -308,7 +308,7 @@ { "ConcreteType": "PythonNodeModels.PythonNode, PythonNodeModels", "Code": "import clr\r\nclr.AddReference('ProtoGeometry')\r\nfrom Autodesk.DesignScript.Geometry import *\r\n#The inputs to this node will be stored as a list in the IN variable.\r\ndataEnteringNode = IN\r\n\r\np1 = Point.ByCoordinates(0, 0, 0);\r\np2 = Point.ByCoordinates(-10, -10, -10);\r\n\r\nl = Line.ByStartPointEndPoint(p1, p2);\r\n\r\npts = [\r\n\tPoint.ByCoordinates(0, 0, 0),\r\n\tPoint.ByCoordinates(10, 10, 0),\r\n\tPoint.ByCoordinates(20, 0, 0),\r\n\tPoint.ByCoordinates(30, 10, 0),\r\n\tPoint.ByCoordinates(40, 0, 0) ]\r\n\t\r\nspline = NurbsCurve.ByPoints(pts)\r\n\r\nsurf = spline.Extrude(Vector.ByCoordinates(0, 0, 1), 10)\r\n\r\n#Assign your output to the OUT variable\r\nOUT = [l, spline, surf]", - "Engine": "CPython3", + "Engine": "PythonNet3", "VariableInputPorts": true, "Id": "9094d23b33384e5caf7b7d08e547cc25", "NodeType": "PythonScriptNode", @@ -345,8 +345,8 @@ "Outputs": [ { "Id": "59d88e24f9a74bff9929b2d9143d29c8", - "Name": "", - "Description": "Value of expression at line 1", + "Name": "function", + "Description": "DesignScript.Builtin.Get.ValueAtIndex(output, 0)", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, @@ -354,8 +354,8 @@ }, { "Id": "0ab66368430d41f2a3854c7b4ff9da7a", - "Name": "", - "Description": "Value of expression at line 2", + "Name": "function", + "Description": "DesignScript.Builtin.Get.ValueAtIndex(output, 1)", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, @@ -363,8 +363,8 @@ }, { "Id": "6a006dc2cf674e36a423c6ef2d9aba6c", - "Name": "", - "Description": "Value of expression at line 3", + "Name": "function", + "Description": "DesignScript.Builtin.Get.ValueAtIndex(output, 2)", "UsingDefaultValue": false, "Level": 2, "UseLevels": false, @@ -378,7 +378,7 @@ { "ConcreteType": "CoreNodeModels.Watch, CoreNodeModels", "WatchWidth": 72.0, - "WatchHeight": 38.0, + "WatchHeight": 40.0, "Id": "df5d88d2dfc542d4b5dd2ded5c79980c", "NodeType": "ExtensionNode", "Inputs": [ @@ -409,7 +409,7 @@ { "ConcreteType": "CoreNodeModels.Watch, CoreNodeModels", "WatchWidth": 420.0, - "WatchHeight": 38.0, + "WatchHeight": 40.0, "Id": "516af1443b9d45b39f0f4864055cf9e0", "NodeType": "ExtensionNode", "Inputs": [ @@ -440,7 +440,7 @@ { "ConcreteType": "CoreNodeModels.Watch, CoreNodeModels", "WatchWidth": 185.0, - "WatchHeight": 38.0, + "WatchHeight": 40.0, "Id": "6d21b7b3707342ed892734d225a90f1a", "NodeType": "ExtensionNode", "Inputs": [ @@ -575,7 +575,7 @@ "ScaleFactor": 1.0, "HasRunWithoutCrash": true, "IsVisibleInDynamoLibrary": true, - "Version": "3.1.0.3411", + "Version": "4.1.0.2940", "RunType": "Automatic", "RunPeriod": "100" }, @@ -752,6 +752,8 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [ "fb28178df0ca4db085105202c26f64cf", "041d63bf18384c6bb45dfa9a7a549434" @@ -760,12 +762,16 @@ "Left": 2553.5609806193347, "Top": 976.9425675710149, "Width": 551.0, - "Height": 371.0, + "Height": 365.0, "FontSize": 36.0, "GroupStyleId": "883066aa-1fe2-44a4-9bd1-c3df86bfe9f6", "InitialTop": 1049.942567571015, - "InitialHeight": 328.1724999999998, + "InitialHeight": 206.3298163756981, "TextblockHeight": 63.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFFFB8D8" }, { @@ -775,20 +781,26 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [ "9e561a4f9f864d4eac53e30110ffb406", "921d119036464fc2a9854b4693a6c026" ], "HasNestedGroups": false, "Left": 2554.1053173739324, - "Top": 593.2415815324191, + "Top": 593.241581532419, "Width": 368.0, - "Height": 349.9999999999999, + "Height": 350.0, "FontSize": 36.0, "GroupStyleId": "883066aa-1fe2-44a4-9bd1-c3df86bfe9f6", - "InitialTop": 709.2415815324191, - "InitialHeight": 264.0, + "InitialTop": 709.241581532419, + "InitialHeight": 246.9999999999999, "TextblockHeight": 106.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFD4B6DB" }, { @@ -798,6 +810,8 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [ "3316bcb825c946cbbb71e61d1f449192" ], @@ -809,8 +823,12 @@ "FontSize": 36.0, "GroupStyleId": "bc688959-ce34-4bf5-90f8-6ddd23f80989", "InitialTop": 251.23676596959353, - "InitialHeight": 252.0, + "InitialHeight": 145.0, "TextblockHeight": 63.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFA4E1FF" }, { @@ -820,6 +838,8 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [ "7183a2fe9a6a4eebb2233525a80ab2f2", "fc54c00a15034189a61233646c89b0da" @@ -828,12 +848,16 @@ "Left": 3189.4043760349814, "Top": 612.8175817692282, "Width": 320.0, - "Height": 365.0, + "Height": 363.0, "FontSize": 36.0, "GroupStyleId": "4d68be4a-a04d-4945-9dd5-cdf61079d790", "InitialTop": 685.8175817692282, - "InitialHeight": 322.0, + "InitialHeight": 275.0, "TextblockHeight": 63.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFB9F9E1" }, { @@ -843,6 +867,8 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [ "ecc8630fa9b040619046b47ce8ba4f2c", "e14a495391154344ac65e7243e4975e3", @@ -853,12 +879,16 @@ "Left": 3625.709690623294, "Top": 993.83718375424, "Width": 874.0000000000005, - "Height": 429.0, + "Height": 423.0, "FontSize": 36.0, "GroupStyleId": "07655dc1-2d65-4fed-8d6a-37235d3e3a8d", "InitialTop": 1066.83718375424, - "InitialHeight": 386.0, + "InitialHeight": 236.82750000000033, "TextblockHeight": 63.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFFFC999" }, { @@ -868,6 +898,8 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [ "b1be50edf93c4d9cb7c455d97e820672", "340d812d39634fffbb4ecfadea6b01ca", @@ -882,8 +914,12 @@ "FontSize": 36.0, "GroupStyleId": "07655dc1-2d65-4fed-8d6a-37235d3e3a8d", "InitialTop": 738.4577717319397, - "InitialHeight": 319.90632856924196, + "InitialHeight": 236.8275000000001, "TextblockHeight": 63.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFFFC999" }, { @@ -893,6 +929,8 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [ "ee76b77e33f840539f33dc43aa97fd98" ], @@ -904,8 +942,12 @@ "FontSize": 36.0, "GroupStyleId": "00000000-0000-0000-0000-000000000000", "InitialTop": 797.6599239566941, - "InitialHeight": 123.0, + "InitialHeight": 145.0, "TextblockHeight": 193.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFA4E1FF" }, { @@ -915,20 +957,26 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [ "9094d23b33384e5caf7b7d08e547cc25", "8d0cb3fc32db4220b727887b354d2867" ], "HasNestedGroups": false, - "Left": 3228.8878662633592, + "Left": 3233.3878662633592, "Top": 1618.4499139083607, "Width": 320.0, "Height": 378.0, "FontSize": 36.0, "GroupStyleId": "4d68be4a-a04d-4945-9dd5-cdf61079d790", "InitialTop": 1734.4499139083607, - "InitialHeight": 292.0, + "InitialHeight": 275.0, "TextblockHeight": 106.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFB9F9E1" }, { @@ -938,6 +986,8 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [ "b643c0d143e443709bdf07f448fb8195", "df5d88d2dfc542d4b5dd2ded5c79980c", @@ -949,12 +999,16 @@ "Left": 3619.9228883935357, "Top": 1665.0310553505428, "Width": 840.0, - "Height": 511.0, + "Height": 507.0, "FontSize": 36.0, "GroupStyleId": "07655dc1-2d65-4fed-8d6a-37235d3e3a8d", "InitialTop": 1738.0310553505428, - "InitialHeight": 468.0, + "InitialHeight": 447.0, "TextblockHeight": 63.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFFFC999" }, { @@ -964,10 +1018,12 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [], "HasNestedGroups": false, "Left": 2636.6053173739324, - "Top": 717.2415815324191, + "Top": 717.241581532419, "Width": 0.0, "Height": 0.0, "FontSize": 36.0, @@ -975,6 +1031,10 @@ "InitialTop": 0.0, "InitialHeight": 0.0, "TextblockHeight": 0.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFC1D676", "PinnedNode": "9e561a4f9f864d4eac53e30110ffb406" }, @@ -985,6 +1045,8 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [], "HasNestedGroups": false, "Left": 2591.0609806193347, @@ -996,6 +1058,10 @@ "InitialTop": 0.0, "InitialHeight": 0.0, "TextblockHeight": 0.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFC1D676", "PinnedNode": "fb28178df0ca4db085105202c26f64cf" }, @@ -1006,6 +1072,8 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [], "HasNestedGroups": false, "Left": 4214.354598893615, @@ -1017,6 +1085,10 @@ "InitialTop": 0.0, "InitialHeight": 0.0, "TextblockHeight": 0.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFC1D676", "PinnedNode": "c44ca1114bbf48cc9b358b339af6c19e" }, @@ -1027,6 +1099,8 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [], "HasNestedGroups": false, "Left": 4267.709690623295, @@ -1038,6 +1112,10 @@ "InitialTop": 0.0, "InitialHeight": 0.0, "TextblockHeight": 0.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFC1D676", "PinnedNode": "ecc8630fa9b040619046b47ce8ba4f2c" }, @@ -1048,6 +1126,8 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [], "HasNestedGroups": false, "Left": 2197.297776501844, @@ -1059,6 +1139,10 @@ "InitialTop": 0.0, "InitialHeight": 0.0, "TextblockHeight": 0.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFC1D676" }, { @@ -1068,6 +1152,8 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [], "HasNestedGroups": false, "Left": 3199.4043760349814, @@ -1079,6 +1165,10 @@ "InitialTop": 0.0, "InitialHeight": 0.0, "TextblockHeight": 0.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFC1D676", "PinnedNode": "7183a2fe9a6a4eebb2233525a80ab2f2" }, @@ -1089,6 +1179,8 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [], "HasNestedGroups": false, "Left": 2195.9549681080157, @@ -1100,6 +1192,10 @@ "InitialTop": 0.0, "InitialHeight": 0.0, "TextblockHeight": 0.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFC1D676" }, { @@ -1109,9 +1205,11 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [], "HasNestedGroups": false, - "Left": 3655.4228883935357, + "Left": 3668.4228883935357, "Top": 1807.5135553505434, "Width": 0.0, "Height": 0.0, @@ -1120,6 +1218,10 @@ "InitialTop": 0.0, "InitialHeight": 0.0, "TextblockHeight": 0.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFC1D676", "PinnedNode": "b643c0d143e443709bdf07f448fb8195" }, @@ -1130,9 +1232,11 @@ "IsExpanded": true, "WidthAdjustment": 0.0, "HeightAdjustment": 0.0, + "UserSetWidth": 0.0, + "UserSetHeight": 0.0, "Nodes": [], "HasNestedGroups": false, - "Left": 3238.8878662633592, + "Left": 3243.3878662633592, "Top": 1742.4499139083607, "Width": 0.0, "Height": 0.0, @@ -1141,6 +1245,10 @@ "InitialTop": 0.0, "InitialHeight": 0.0, "TextblockHeight": 0.0, + "IsOptionalInPortsCollapsed": false, + "IsUnconnectedOutPortsCollapsed": false, + "HasToggledOptionalInPorts": false, + "HasToggledUnconnectedOutPorts": false, "Background": "#FFC1D676", "PinnedNode": "9094d23b33384e5caf7b7d08e547cc25" } diff --git a/extern/Python/Python.Included.SciPy.dll b/extern/Python/Python.Included.SciPy.dll deleted file mode 100644 index 799c574aac8..00000000000 Binary files a/extern/Python/Python.Included.SciPy.dll and /dev/null differ diff --git a/extern/Python/Python.Included.dll b/extern/Python/Python.Included.dll deleted file mode 100644 index 8628b60312b..00000000000 Binary files a/extern/Python/Python.Included.dll and /dev/null differ diff --git a/extern/Python/Python.Runtime.dll b/extern/Python/Python.Runtime.dll deleted file mode 100644 index bd9c125b7f8..00000000000 Binary files a/extern/Python/Python.Runtime.dll and /dev/null differ diff --git a/src/Dynamo.All.sln b/src/Dynamo.All.sln index 5ea0a8170cd..c8bfd2a9c47 100644 --- a/src/Dynamo.All.sln +++ b/src/Dynamo.All.sln @@ -79,8 +79,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DynamoFeatureFlags", "Tools EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Analysis", "Libraries\Analysis\Analysis.csproj", "{76686ED6-E759-4772-81C2-768740BE13FA}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DSCPython", "Libraries\DSCPython\DSCPython.csproj", "{F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeometryColor", "Libraries\GeometryColor\GeometryColor.csproj", "{A50C198C-DA6E-4081-BC53-0F44D287F207}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeometryUI", "Libraries\GeometryUI\GeometryUI.csproj", "{E674F1A1-BE83-475A-9CC9-F55CADBEC448}" @@ -305,10 +303,6 @@ Global {76686ED6-E759-4772-81C2-768740BE13FA}.Debug|Any CPU.Build.0 = Debug|Any CPU {76686ED6-E759-4772-81C2-768740BE13FA}.Release|Any CPU.ActiveCfg = Release|Any CPU {76686ED6-E759-4772-81C2-768740BE13FA}.Release|Any CPU.Build.0 = Release|Any CPU - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Release|Any CPU.Build.0 = Release|Any CPU {A50C198C-DA6E-4081-BC53-0F44D287F207}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A50C198C-DA6E-4081-BC53-0F44D287F207}.Debug|Any CPU.Build.0 = Debug|Any CPU {A50C198C-DA6E-4081-BC53-0F44D287F207}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -569,7 +563,6 @@ Global {C0D6DEE5-5532-4345-9C66-4C00D7FDB8BE} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} {94CF053D-BB66-4FC7-883B-48F072701BA9} = {D114C59C-CF66-4CC2-980F-9301FB4EA4E1} {76686ED6-E759-4772-81C2-768740BE13FA} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} {A50C198C-DA6E-4081-BC53-0F44D287F207} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} {E674F1A1-BE83-475A-9CC9-F55CADBEC448} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} {8872CA17-C10D-43B9-8393-5C5A57065EB0} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} diff --git a/src/DynamoCore.sln b/src/DynamoCore.sln index 554bc3cbed2..f4e34fc424e 100644 --- a/src/DynamoCore.sln +++ b/src/DynamoCore.sln @@ -77,8 +77,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssemblyInfoGenerator", "As EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Analysis", "Libraries\Analysis\Analysis.csproj", "{76686ED6-E759-4772-81C2-768740BE13FA}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DSCPython", "Libraries\DSCPython\DSCPython.csproj", "{F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeometryColor", "Libraries\GeometryColor\GeometryColor.csproj", "{A50C198C-DA6E-4081-BC53-0F44D287F207}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeometryUI", "Libraries\GeometryUI\GeometryUI.csproj", "{E674F1A1-BE83-475A-9CC9-F55CADBEC448}" @@ -385,18 +383,6 @@ Global {76686ED6-E759-4772-81C2-768740BE13FA}.Release|NET_Linux.Build.0 = Release|NET_Linux {76686ED6-E759-4772-81C2-768740BE13FA}.Release|Publish_Linux.ActiveCfg = Release|Publish_Linux {76686ED6-E759-4772-81C2-768740BE13FA}.Release|Publish_Linux.Build.0 = Release|Publish_Linux - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Debug|NET_Linux.ActiveCfg = Debug|NET_Linux - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Debug|NET_Linux.Build.0 = Debug|NET_Linux - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Debug|Publish_Linux.ActiveCfg = Debug|Publish_Linux - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Debug|Publish_Linux.Build.0 = Debug|Publish_Linux - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Release|Any CPU.Build.0 = Release|Any CPU - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Release|NET_Linux.ActiveCfg = Release|NET_Linux - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Release|NET_Linux.Build.0 = Release|NET_Linux - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Release|Publish_Linux.ActiveCfg = Release|Publish_Linux - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479}.Release|Publish_Linux.Build.0 = Release|Publish_Linux {A50C198C-DA6E-4081-BC53-0F44D287F207}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A50C198C-DA6E-4081-BC53-0F44D287F207}.Debug|Any CPU.Build.0 = Debug|Any CPU {A50C198C-DA6E-4081-BC53-0F44D287F207}.Debug|NET_Linux.ActiveCfg = Debug|NET_Linux @@ -623,7 +609,6 @@ Global {47533B7C-0E1A-44A4-8511-B438645F052A} = {88D45B00-E564-41DB-B57C-9509646CAA49} {C0D6DEE5-5532-4345-9C66-4C00D7FDB8BE} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} {76686ED6-E759-4772-81C2-768740BE13FA} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} {A50C198C-DA6E-4081-BC53-0F44D287F207} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} {E674F1A1-BE83-475A-9CC9-F55CADBEC448} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} {8872CA17-C10D-43B9-8393-5C5A57065EB0} = {FA7BE306-A3B0-45FA-9D87-0C69E6932C13} diff --git a/src/DynamoCore/Configuration/PreferenceSettings.cs b/src/DynamoCore/Configuration/PreferenceSettings.cs index c6bb024a1ba..eec7f3304fa 100644 --- a/src/DynamoCore/Configuration/PreferenceSettings.cs +++ b/src/DynamoCore/Configuration/PreferenceSettings.cs @@ -707,6 +707,17 @@ public string PythonTemplateFilePath /// public bool ShowTabsAndSpacesInScriptEditor { get; set; } + /// + /// Controls whether Dynamo shows upgrade notifications for legacy CPython nodes + /// when opening a graph. These notices appear when a graph contains CPython-engine + /// Python nodes that are automatically upgraded to PythonNet3: + /// • toast on graph open + /// • save/close confirmation dialog + /// • banner inside the Python Script Editor + /// NOTE: This setting is not related to the historical IronPython2 → CPython3 migration. + /// + public bool HideCPython3Notifications { get; set; } = false; + /// /// This defines if user wants to see the enabled node Auto Complete feature for port interaction. /// diff --git a/src/DynamoCore/DynamoCore.csproj b/src/DynamoCore/DynamoCore.csproj index ea46878e9ff..c4a78649a14 100644 --- a/src/DynamoCore/DynamoCore.csproj +++ b/src/DynamoCore/DynamoCore.csproj @@ -40,7 +40,8 @@ - + + @@ -224,6 +225,28 @@ + + + + $(OutputPath)Built-In Packages\packages\PythonNet3Engine\ + $(DestRoot)bin\ + $(DestRoot)extra\ + $(PkgDynamoVisualProgramming_PythonEngine_PythonNet3) + $(PkgRoot)\lib\ + $(PkgRoot)\content\manifest\pkg.json + + + + + + + + + + + + + diff --git a/src/DynamoCore/Graph/Workspaces/WorkspaceModel.cs b/src/DynamoCore/Graph/Workspaces/WorkspaceModel.cs index 353d161ebff..74cf5cbca45 100644 --- a/src/DynamoCore/Graph/Workspaces/WorkspaceModel.cs +++ b/src/DynamoCore/Graph/Workspaces/WorkspaceModel.cs @@ -304,6 +304,11 @@ internal int CurrentPasteOffset private Dictionary externalFilesDictionary = new Dictionary(); private readonly string customNodeExtension = ".dyf"; + /// + /// Flag to indicate whether the CPython notification has been shown once. + /// + internal bool HasShownCPythonNotification; + /// /// Whether or not to delay graph execution. /// 64-bit read operations are already atomic so no need to lock here @@ -1384,6 +1389,14 @@ internal set WorkspaceEvents.OnWorkspaceSettingsChanged(scaleFactor); } } + + /// + /// Flag indicating whether the “Python Engine Change” notice should be shown + /// on save/close. Runtime-only (not serialized) and reset on workspace switch. + /// + [JsonIgnore] + public bool ShowCPythonNotifications { get; internal set; } + #endregion #region constructors diff --git a/src/DynamoCoreWpf/Properties/Resources.Designer.cs b/src/DynamoCoreWpf/Properties/Resources.Designer.cs index e447fa504f7..f744a38937d 100644 --- a/src/DynamoCoreWpf/Properties/Resources.Designer.cs +++ b/src/DynamoCoreWpf/Properties/Resources.Designer.cs @@ -1004,6 +1004,34 @@ public static string CopyToClipboardTooltip { return ResourceManager.GetString("CopyToClipboardTooltip", resourceCulture); } } + + /// + /// Looks up a localized string similar to Python Engine Change. + /// + public static string CPython3EngineNotificationMessageBoxHeader { + get { + return ResourceManager.GetString("CPython3EngineNotificationMessageBoxHeader", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This graph includes CPython nodes, which are no longer supported in Dynamo 4.0. Saving will convert them to PythonNet3, the new default engine. + ///To open this graph in Dynamo 3.3–3.6.x: Install the PythonNet package from the Package Manager.. + /// + public static string CPython3EngineNotificationMessageBoxText { + get { + return ResourceManager.GetString("CPython3EngineNotificationMessageBoxText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to https://dynamobim.org/pythonnet3-a-new-dynamo-python-to-fix-everything/. + /// + public static string CPython3EngineUpgradeLearnMoreUri { + get { + return ResourceManager.GetString("CPython3EngineUpgradeLearnMoreUri", resourceCulture); + } + } /// /// Looks up a localized string similar to Copy. @@ -4462,6 +4490,15 @@ public static string MessageAlreadyInstallDynamo { return ResourceManager.GetString("MessageAlreadyInstallDynamo", resourceCulture); } } + + /// + /// Looks up a localized string similar to Don't show this again. + /// + public static string MessageBoxDontShowAgainLabel { + get { + return ResourceManager.GetString("MessageBoxDontShowAgainLabel", resourceCulture); + } + } /// /// Looks up a localized string similar to Are you sure you want to delete {0} ? This will delete the packages root directory. @@ -8315,6 +8352,24 @@ public static string PreferencesViewHideOutportsDescription { } } + /// + /// Looks up a localized string similar to Hide Python Engine change notifications. + /// + public static string PreferencesViewHidePythonEngineChangeNotifications { + get { + return ResourceManager.GetString("PreferencesViewHidePythonEngineChangeNotifications", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CPython is no longer supported in Dynamo 4.0 or above and will be converted to the new default engine PythonNet3. Disable the toggle to hide all notifications about engine changes.. + /// + public static string PreferencesViewHidePythonEngineChangeNotificationsTooltip { + get { + return ResourceManager.GetString("PreferencesViewHidePythonEngineChangeNotificationsTooltip", resourceCulture); + } + } + /// /// Looks up a localized string similar to When toggled on, file names of exported images include date and time of export.. /// @@ -9619,20 +9674,20 @@ public static string ResetChangesWarningPopupMessage { } /// - /// Looks up a localized string similar to Reset CPython. + /// Looks up a localized string similar to Reset PythonNet3. /// - public static string ResetCPythonButtonText { + public static string ResetPythonNet3ButtonText { get { - return ResourceManager.GetString("ResetCPythonButtonText", resourceCulture); + return ResourceManager.GetString("ResetPythonNet3ButtonText", resourceCulture); } } /// - /// Looks up a localized string similar to Resets CPython environment by reloading modules.. + /// Looks up a localized string similar to Resets PythonNet3 environment by reloading modules.. /// - public static string ResetCPythonButtonToolTip { + public static string ResetPythonNet3ButtonToolTip { get { - return ResourceManager.GetString("ResetCPythonButtonToolTip", resourceCulture); + return ResourceManager.GetString("ResetPythonNet3ButtonToolTip", resourceCulture); } } diff --git a/src/DynamoCoreWpf/Properties/Resources.en-US.resx b/src/DynamoCoreWpf/Properties/Resources.en-US.resx index 8ef1e123ab6..c21bd5d286b 100644 --- a/src/DynamoCoreWpf/Properties/Resources.en-US.resx +++ b/src/DynamoCoreWpf/Properties/Resources.en-US.resx @@ -2594,11 +2594,11 @@ Do you wish to uninstall {1}? Restart {2} to complete the uninstall and try down Add Style - - Reset CPython + + Reset PythonNet3 - - Resets CPython environment by reloading modules. + + Resets PythonNet3 environment by reloading modules. Cancel and Show Issues @@ -4213,10 +4213,29 @@ To make this file into a new template, save it to a different folder, then move Hide unconnected output ports by default + + Hide Python Engine change notifications + + + CPython is no longer supported in Dynamo 4.0 or above and will be converted to the new default engine PythonNet3. Disable the toggle to hide all notifications about engine changes. + + + Don't show this again + + + Python Engine Change + + + This graph includes CPython nodes, which are no longer supported in Dynamo 4.0. Saving will convert them to PythonNet3, the new default engine. +To open this graph in Dynamo 3.3–3.6.x: Install the PythonNet package from the Package Manager. + + + https://dynamobim.org/pythonnet3-a-new-dynamo-python-to-fix-everything/ + Connected to the internet. Not connected to the internet. - \ No newline at end of file + diff --git a/src/DynamoCoreWpf/Properties/Resources.resx b/src/DynamoCoreWpf/Properties/Resources.resx index 967bf8ec0f8..87bdc34dac8 100644 --- a/src/DynamoCoreWpf/Properties/Resources.resx +++ b/src/DynamoCoreWpf/Properties/Resources.resx @@ -2889,11 +2889,11 @@ Do you wish to uninstall {1}? Restart {2} to complete the uninstall and try down Add Style - - Reset CPython + + Reset PythonNet3 - - Resets CPython environment by reloading modules. + + Resets PythonNet3 environment by reloading modules. Cancel and Show Issues @@ -4200,10 +4200,29 @@ To make this file into a new template, save it to a different folder, then move Hide unconnected output ports by default + + Hide Python Engine change notifications + + + CPython is no longer supported in Dynamo 4.0 or above and will be converted to the new default engine PythonNet3. Disable the toggle to hide all notifications about engine changes. + + + Don't show this again + + + Python Engine Change + + + This graph includes CPython nodes, which are no longer supported in Dynamo 4.0. Saving will convert them to PythonNet3, the new default engine. +To open this graph in Dynamo 3.3–3.6.x: Install the PythonNet package from the Package Manager. + + + https://dynamobim.org/pythonnet3-a-new-dynamo-python-to-fix-everything/ + Connected to the internet. Not connected to the internet. - \ No newline at end of file + diff --git a/src/DynamoCoreWpf/PublicAPI.Unshipped.txt b/src/DynamoCoreWpf/PublicAPI.Unshipped.txt index 86bed3d319b..a09cee1419c 100644 --- a/src/DynamoCoreWpf/PublicAPI.Unshipped.txt +++ b/src/DynamoCoreWpf/PublicAPI.Unshipped.txt @@ -2171,6 +2171,7 @@ Dynamo.ViewModels.DynamoViewModel.PublishNewPackageCommand.get -> Dynamo.UI.Comm Dynamo.ViewModels.DynamoViewModel.PublishNewPackageCommand.set -> void Dynamo.ViewModels.DynamoViewModel.PublishSelectedNodesCommand.get -> Dynamo.UI.Commands.DelegateCommand Dynamo.ViewModels.DynamoViewModel.PublishSelectedNodesCommand.set -> void +Dynamo.ViewModels.DynamoViewModel.PythonEngineUpgradeToastRequested -> System.Action Dynamo.ViewModels.DynamoViewModel.RecentFiles.get -> System.Collections.ObjectModel.ObservableCollection Dynamo.ViewModels.DynamoViewModel.RecentFiles.set -> void Dynamo.ViewModels.DynamoViewModel.RedoCommand.get -> Dynamo.UI.Commands.DelegateCommand @@ -2209,6 +2210,7 @@ Dynamo.ViewModels.DynamoViewModel.ScaleFactorLog.set -> void Dynamo.ViewModels.DynamoViewModel.SelectAll(object parameter) -> void Dynamo.ViewModels.DynamoViewModel.SelectAllCommand.get -> Dynamo.UI.Commands.DelegateCommand Dynamo.ViewModels.DynamoViewModel.SelectAllCommand.set -> void +Dynamo.ViewModels.DynamoViewModel.ShowPythonEngineUpgradeCanvasToast(string message, bool stayOpen = true) -> void Dynamo.ViewModels.DynamoViewModel.ShowGraphPropertiesCommand.get -> Dynamo.UI.Commands.DelegateCommand Dynamo.ViewModels.DynamoViewModel.ShowGraphPropertiesCommand.set -> void Dynamo.ViewModels.DynamoViewModel.UnpinAllPreviewBubbles(object parameter) -> void @@ -2872,6 +2874,8 @@ Dynamo.ViewModels.PreferencesViewModel.Filters.get -> System.Collections.ObjectM Dynamo.ViewModels.PreferencesViewModel.GroupStyleFontSizeList.get -> System.Collections.ObjectModel.ObservableCollection Dynamo.ViewModels.PreferencesViewModel.GroupStyleFontSizeList.set -> void Dynamo.ViewModels.PreferencesViewModel.HideAutocompleteMethodOptions.get -> bool +Dynamo.ViewModels.PreferencesViewModel.HideCPythonNotificationIsChecked.get -> bool +Dynamo.ViewModels.PreferencesViewModel.HideCPythonNotificationIsChecked.set -> void Dynamo.ViewModels.PreferencesViewModel.HideNodesBelowSpecificConfidenceLevelIsChecked.get -> bool Dynamo.ViewModels.PreferencesViewModel.HideNodesBelowSpecificConfidenceLevelIsChecked.set -> void Dynamo.ViewModels.PreferencesViewModel.HostGenericScaleUnits.get -> string @@ -4310,8 +4314,18 @@ Dynamo.Wpf.Views.GuidedTour.RatingControl.RatingControl() -> void Dynamo.Wpf.Views.GuidedTour.RatingControl.Value.get -> int Dynamo.Wpf.Views.GuidedTour.RatingControl.Value.set -> void Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow +Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.HeaderContent.get -> string +Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.HeaderContent.set -> void +Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.HyperlinkText.get -> string +Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.HyperlinkText.set -> void +Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.HyperlinkUri.get -> System.Uri +Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.HyperlinkUri.set -> void Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.InitializeComponent() -> void Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.RealTimeInfoWindow() -> void +Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.ShowHeader.get -> bool +Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.ShowHeader.set -> void +Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.ShowHyperlink.get -> bool +Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.ShowHyperlink.set -> void Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.TextContent.get -> string Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.TextContent.set -> void Dynamo.Wpf.Views.GuidedTour.RealTimeInfoWindow.UpdateLocation() -> void @@ -4525,6 +4539,7 @@ static Dynamo.UI.Prompts.DynamoMessageBox.Show(string messageBoxText, string cap static Dynamo.UI.Prompts.DynamoMessageBox.Show(System.Windows.Window owner, string messageBoxText, string caption, bool showRichTextBox, System.Windows.MessageBoxButton button, System.Windows.MessageBoxImage icon) -> System.Windows.MessageBoxResult static Dynamo.UI.Prompts.DynamoMessageBox.Show(System.Windows.Window owner, string messageBoxText, string caption, System.Collections.Generic.Dictionary flags, System.Windows.MessageBoxButton button, System.Windows.MessageBoxImage icon) -> System.Windows.MessageBoxResult static Dynamo.UI.Prompts.DynamoMessageBox.Show(System.Windows.Window owner, string messageBoxText, string caption, System.Windows.MessageBoxButton button, System.Windows.MessageBoxImage icon) -> System.Windows.MessageBoxResult +static Dynamo.UI.Prompts.DynamoMessageBox.ShowWithCheckbox(System.Windows.Window owner, string messageBoxText, string caption, System.Windows.MessageBoxButton button, System.Collections.Generic.IEnumerable buttonNames, System.Windows.MessageBoxImage icon, string checkboxText, out bool isChecked) -> System.Windows.MessageBoxResult static Dynamo.UI.SharedDictionaryManager.ConnectorsDictionary.get -> System.Windows.ResourceDictionary static Dynamo.UI.SharedDictionaryManager.ConnectorsDictionaryUri.get -> System.Uri static Dynamo.UI.SharedDictionaryManager.DataTemplatesDictionary.get -> System.Windows.ResourceDictionary @@ -4670,6 +4685,9 @@ static Dynamo.Wpf.Properties.Resources.ConverterMessageTransformOrigin.get -> st static Dynamo.Wpf.Properties.Resources.ConverterMessageZoom.get -> string static Dynamo.Wpf.Properties.Resources.CopyToClipboardTooltip.get -> string static Dynamo.Wpf.Properties.Resources.CopyToClipboardFailedMessage.get -> string +static Dynamo.Wpf.Properties.Resources.CPython3EngineNotificationMessageBoxHeader.get -> string +static Dynamo.Wpf.Properties.Resources.CPython3EngineNotificationMessageBoxText.get -> string +static Dynamo.Wpf.Properties.Resources.CPython3EngineUpgradeLearnMoreUri.get -> string static Dynamo.Wpf.Properties.Resources.CrashPromptDialogCopyButton.get -> string static Dynamo.Wpf.Properties.Resources.CrashPromptDialogCrashMessage.get -> string static Dynamo.Wpf.Properties.Resources.CrashPromptDialogDetailButton.get -> string @@ -5055,6 +5073,7 @@ static Dynamo.Wpf.Properties.Resources.LogoutMenuItemText.get -> string static Dynamo.Wpf.Properties.Resources.MajorVersionNonNegative.get -> string static Dynamo.Wpf.Properties.Resources.Manual.get -> string static Dynamo.Wpf.Properties.Resources.MessageAlreadyInstallDynamo.get -> string +static Dynamo.Wpf.Properties.Resources.MessageBoxDontShowAgainLabel.get -> string static Dynamo.Wpf.Properties.Resources.MessageConfirmToDeletePackage.get -> string static Dynamo.Wpf.Properties.Resources.MessageConfirmToInstallPackage.get -> string static Dynamo.Wpf.Properties.Resources.MessageConfirmToInstallPackageToFolder.get -> string @@ -5477,6 +5496,8 @@ static Dynamo.Wpf.Properties.Resources.PreferencesViewGeneralTab.get -> string static Dynamo.Wpf.Properties.Resources.PreferencesViewGroupStylesHeader.get -> string static Dynamo.Wpf.Properties.Resources.PreferencesViewHideInportsDescription.get -> string static Dynamo.Wpf.Properties.Resources.PreferencesViewHideOutportsDescription.get -> string +static Dynamo.Wpf.Properties.Resources.PreferencesViewHidePythonEngineChangeNotifications.get -> string +static Dynamo.Wpf.Properties.Resources.PreferencesViewHidePythonEngineChangeNotificationsTooltip.get -> string static Dynamo.Wpf.Properties.Resources.PreferencesViewIncludeTimestampExportPathTooltip.get -> string static Dynamo.Wpf.Properties.Resources.PreferencesViewLanguageLabel.get -> string static Dynamo.Wpf.Properties.Resources.PreferencesViewLanguageSwitchHelp.get -> string @@ -5622,8 +5643,8 @@ static Dynamo.Wpf.Properties.Resources.RenderingMemoryOutageSummary.get -> strin static Dynamo.Wpf.Properties.Resources.RerunButton.get -> string static Dynamo.Wpf.Properties.Resources.RerunButtonToolTip.get -> string static Dynamo.Wpf.Properties.Resources.ResetChangesWarningPopupMessage.get -> string -static Dynamo.Wpf.Properties.Resources.ResetCPythonButtonText.get -> string -static Dynamo.Wpf.Properties.Resources.ResetCPythonButtonToolTip.get -> string +static Dynamo.Wpf.Properties.Resources.ResetPythonNet3ButtonText.get -> string +static Dynamo.Wpf.Properties.Resources.ResetPythonNet3ButtonToolTip.get -> string static Dynamo.Wpf.Properties.Resources.ResourceManager.get -> System.Resources.ResourceManager static Dynamo.Wpf.Properties.Resources.RunBlockedMessage.get -> string static Dynamo.Wpf.Properties.Resources.RunCompletedMessage.get -> string diff --git a/src/DynamoCoreWpf/UI/GuidedTour/GuidesManager.cs b/src/DynamoCoreWpf/UI/GuidedTour/GuidesManager.cs index ae1f1066f33..432264daeed 100644 --- a/src/DynamoCoreWpf/UI/GuidedTour/GuidesManager.cs +++ b/src/DynamoCoreWpf/UI/GuidedTour/GuidesManager.cs @@ -543,8 +543,20 @@ private void Popup_StepClosed(string name, Step.StepTypes stepType) /// /// The target content to display. /// boolean indicates if the popup will stay open until user dismiss it. + /// The header text to display. + /// boolean indicates if the header will be shown. + /// boolean indicates if the hyperlink will be shown. + /// The hyperlink text to display. + /// The hyperlink uri to navigate to. /// TODO: Make this API out of guide manager to a more generic place - internal void CreateRealTimeInfoWindow(string content, bool stayOpen = false) + internal void CreateRealTimeInfoWindow( + string content, + bool stayOpen = false, + bool showHeader = false, + string headerText = "", + bool showHyperlink = false, + string hyperlinkText = "", + Uri hyperlinkUri = null) { //Search a UIElement with the Name "statusBarPanel" inside the Dynamo VisualTree UIElement hostUIElement = GuideUtilities.FindChild(mainRootElement, "statusBarPanel"); @@ -559,7 +571,12 @@ internal void CreateRealTimeInfoWindow(string content, bool stayOpen = false) HorizontalOffset = ExitTourHorizontalOffset, Placement = PlacementMode.Left, TextContent = content, - StaysOpen = stayOpen + StaysOpen = stayOpen, + ShowHeader = showHeader, + HeaderContent = headerText, + ShowHyperlink = showHyperlink, + HyperlinkText = hyperlinkText, + HyperlinkUri = hyperlinkUri }; if (hostUIElement != null) diff --git a/src/DynamoCoreWpf/UI/Prompts/DynamoMessageBox.xaml b/src/DynamoCoreWpf/UI/Prompts/DynamoMessageBox.xaml index 0db9776a66c..8554cfb8fe6 100644 --- a/src/DynamoCoreWpf/UI/Prompts/DynamoMessageBox.xaml +++ b/src/DynamoCoreWpf/UI/Prompts/DynamoMessageBox.xaml @@ -49,6 +49,7 @@ + @@ -171,9 +172,26 @@ Style="{StaticResource CustomRichTextBoxStyle}"> + + + + + diff --git a/src/DynamoCoreWpf/UI/Prompts/DynamoMessageBox.xaml.cs b/src/DynamoCoreWpf/UI/Prompts/DynamoMessageBox.xaml.cs index 4b6d7ec11bc..7fede876648 100644 --- a/src/DynamoCoreWpf/UI/Prompts/DynamoMessageBox.xaml.cs +++ b/src/DynamoCoreWpf/UI/Prompts/DynamoMessageBox.xaml.cs @@ -25,6 +25,7 @@ public partial class DynamoMessageBox : INotifyPropertyChanged private string bodyText; private MessageBoxButton messageBoxButton; private MessageBoxImage messageBoxImage; + private bool extraCheckBoxChecked; #endregion #region Public Properties @@ -160,6 +161,47 @@ public static MessageBoxResult Show(string messageBoxText, string caption, Messa return dynamoMessageBox.CustomDialogResult; } + /// + /// Displays a dialog to the user and returns their choice as a MessageBoxResult. + /// + public static MessageBoxResult ShowWithCheckbox( + Window owner, + string messageBoxText, + string caption, + MessageBoxButton button, + IEnumerable buttonNames, + MessageBoxImage icon, + string checkboxText, + out bool isChecked) + { + var dynamoMessageBox = new DynamoMessageBox + { + BodyText = messageBoxText, + TitleText = caption, + MessageBoxButton = button, + MessageBoxImage = icon, + }; + + SetOwnerWindow(owner, dynamoMessageBox); + dynamoMessageBox.ConfigureButtons(button, buttonNames); + + if (string.IsNullOrWhiteSpace(checkboxText)) + { + dynamoMessageBox.ExtraCheckPanel.Visibility = Visibility.Collapsed; + } + else + { + dynamoMessageBox.ExtraCheckPanel.Visibility = Visibility.Visible; + dynamoMessageBox.ExtraCheckBoxLabel.Content = checkboxText; + dynamoMessageBox.ExtraCheckBox.IsChecked = false; + } + + dynamoMessageBox.ShowDialog(); + + // Capture the checkbox state + isChecked = (dynamoMessageBox.ExtraCheckBox?.IsChecked) ?? false; + return dynamoMessageBox.CustomDialogResult; + } /// /// Displays a dialog to the user and returns their choice as a MessageBoxResult. diff --git a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs index 2ced470065f..09c98cb5ec2 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs @@ -1157,6 +1157,23 @@ internal void OnNodeViewReady(object nodeView) } } + /// + /// Raised by to ask listeners (e.g., Python migration UX) + /// whether a Python engine changed notice should be shown to the user. + /// + internal event EventHandler RequestPythonEngineChangeNotice; + + /// + /// Raises and returns whether any subscriber + /// requested to cancel showing the Python engine changed notice. + /// + internal bool RaiseRequestPythonEngineChangeNotice() + { + var args = new CancelEventArgs(); + RequestPythonEngineChangeNotice?.Invoke(this, args); + return args.Cancel; + } + /// /// Returns whether the IDSDK is initialized or not for Dynamo Sandbox, in host environment defaults to true. /// If showWarning is true, a warning message will be shown to the user if the IDSDK is not initialized. @@ -2430,6 +2447,20 @@ private void model_RequestNotification(string notification, bool stayOpen = fals model?.Logger?.Log(notification); } + /// + /// Raised when a toast should be shown to inform about a CPython to PythonNet3 engine upgrade + /// + public event Action PythonEngineUpgradeToastRequested; + + /// + /// Requests the UI to show a Python-engine-upgrade toast on the canvas. + /// This is UI-agnostic; the View decides when/where to render. + /// + public void ShowPythonEngineUpgradeCanvasToast(string message, bool stayOpen = true) + { + PythonEngineUpgradeToastRequested?.Invoke(message, stayOpen); + } + /// /// Present the open dialog and open the workspace that is selected. /// - If template is selected, opens the template folder @@ -3090,8 +3121,17 @@ x is CodeBlockNodeModel || public void ShowSaveDialogIfNeededAndSaveResult(object parameter) { var vm = this; + var currentWorkspace = vm.Model.CurrentWorkspace; + + // First-time CPython notice when saving a *new, unsaved* Home workspace + if (currentWorkspace.ShowCPythonNotifications + && !currentWorkspace.HasShownCPythonNotification) + { + var cancel = RaiseRequestPythonEngineChangeNotice(); + if (cancel) return; + } - if (string.IsNullOrEmpty(vm.Model.CurrentWorkspace.FileName) || vm.Model.CurrentWorkspace.IsTemplate) + if (string.IsNullOrEmpty(currentWorkspace.FileName) || currentWorkspace.IsTemplate) { if (CanShowSaveDialogAndSaveResult(parameter)) { diff --git a/src/DynamoCoreWpf/ViewModels/Menu/PreferencesViewModel.cs b/src/DynamoCoreWpf/ViewModels/Menu/PreferencesViewModel.cs index 11d7f629527..978b0650b0e 100644 --- a/src/DynamoCoreWpf/ViewModels/Menu/PreferencesViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Menu/PreferencesViewModel.cs @@ -1077,6 +1077,19 @@ public bool ShowWhitespaceIsChecked } } + /// + /// Controls the IsChecked property in the "Hide CPython notifications" toggle button + /// + public bool HideCPythonNotificationIsChecked + { + get => preferenceSettings.HideCPython3Notifications; + set + { + preferenceSettings.HideCPython3Notifications = value; + RaisePropertyChanged(nameof(HideCPythonNotificationIsChecked)); + } + } + /// /// Controls the IsChecked property in the "Notification Center" toggle button /// @@ -1887,6 +1900,9 @@ private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e) case nameof(ShowWhitespaceIsChecked): description = Res.ResourceManager.GetString(nameof(Res.PreferencesViewShowWhitespaceInPythonEditor), System.Globalization.CultureInfo.InvariantCulture); goto default; + case nameof(HideCPythonNotificationIsChecked): + description = Res.ResourceManager.GetString(nameof(Res.PreferencesViewHidePythonEngineChangeNotifications), System.Globalization.CultureInfo.InvariantCulture); + goto default; case nameof(NodeAutocompleteIsChecked): description = Res.ResourceManager.GetString(nameof(Res.PreferencesViewEnableNodeAutoComplete), System.Globalization.CultureInfo.InvariantCulture); goto default; diff --git a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs index 61025670836..4e36902a1d5 100644 --- a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs @@ -30,6 +30,7 @@ using Dynamo.Selection; using Dynamo.Services; using Dynamo.UI.Controls; +using Dynamo.UI.Prompts; using Dynamo.Utilities; using Dynamo.ViewModels; using Dynamo.Views; @@ -484,6 +485,23 @@ private void OnWorkspaceSaving(WorkspaceModel workspace, Graph.SaveContext saveC dynamoViewModel?.CheckOnlineAccess(); } + private void OnPythonEngineUpgradeToastRequested(string msg, bool stayOpen) + { + Dispatcher.BeginInvoke( + System.Windows.Threading.DispatcherPriority.ContextIdle, + new Action(() => + { + dynamoViewModel.MainGuideManager?.CreateRealTimeInfoWindow( + msg, + stayOpen, + showHeader: true, + headerText: Res.CPython3EngineNotificationMessageBoxHeader, + showHyperlink: true, + hyperlinkText: Res.LearnMore, + hyperlinkUri: new Uri(Res.CPython3EngineUpgradeLearnMoreUri)); + })); + } + /// /// Adds an extension control or if it already exists it makes sure it is focused. /// The control may be added as a window or a tab in the extension bar depending on settings. @@ -1417,6 +1435,11 @@ private void DynamoView_Loaded(object sender, EventArgs e) // Initialize Guide Manager as a member on Dynamo ViewModel so other than guided tour, // other part of application can also leverage it. dynamoViewModel.MainGuideManager = new GuidesManager(_this, dynamoViewModel); + + // Subscribes to Python-engine-upgrade toast requests from the ViewModel and + // forwards them to GuidesManager on the UI thread + dynamoViewModel.PythonEngineUpgradeToastRequested += OnPythonEngineUpgradeToastRequested; + GuideFlowEvents.GuidedTourStart += GuideFlowEvents_GuidedTourStart; _timer.Stop(); dynamoViewModel.Model.Logger.Log(String.Format(Wpf.Properties.Resources.MessageLoadingTime, @@ -1462,6 +1485,8 @@ private void DynamoView_Loaded(object sender, EventArgs e) dynamoViewModel.RequestUserSaveWorkflow += DynamoViewModelRequestUserSaveWorkflow; + dynamoViewModel.RequestPythonEngineChangeNotice += DynamoViewModel_RequestPythonEngineChangeNotice; + dynamoViewModel.Model.ClipBoard.CollectionChanged += ClipBoard_CollectionChanged; //ABOUT WINDOW @@ -1724,6 +1749,18 @@ private void DynamoViewModelRequestUserSaveWorkflow(object sender, WorkspaceSave } } + // Show the one-time Python Engine Change notification for the workspace + var ws = dynamoViewModel.Model.CurrentWorkspace; + if (!ws.HasShownCPythonNotification && ws.ShowCPythonNotifications) + { + var cancelFirstDialogBox = ShowPythonEngineChangeNoticeAndMarkIfProceed(); + if (cancelFirstDialogBox) + { + e.Success = false; + return; + } + } + var buttons = e.AllowCancel ? MessageBoxButton.YesNoCancel : MessageBoxButton.YesNo; var result = MessageBoxService.Show(this, dialogText, Dynamo.Wpf.Properties.Resources.UnsavedChangesMessageBoxTitle, @@ -1748,6 +1785,46 @@ private void DynamoViewModelRequestUserSaveWorkflow(object sender, WorkspaceSave } } + private void DynamoViewModel_RequestPythonEngineChangeNotice(object sender, CancelEventArgs e) + { + e.Cancel = ShowPythonEngineChangeNoticeAndMarkIfProceed(); + } + + private bool ShowPythonEngineChangeNoticeAndMarkIfProceed() + { + var ws = dynamoViewModel.Model.CurrentWorkspace; + if (!(ws is HomeWorkspaceModel) && !(string.IsNullOrEmpty(ws?.FileName)) && ws.HasShownCPythonNotification) return false; + + bool dontShowAgain; + + var result = DynamoMessageBox.ShowWithCheckbox( + owner: this, + messageBoxText: Res.CPython3EngineNotificationMessageBoxText, + caption: Res.CPython3EngineNotificationMessageBoxHeader, + button: MessageBoxButton.YesNo, + buttonNames: new[] { Res.GenericTaskDialogOptionOK, Res.LearnMore }, + icon: MessageBoxImage.Information, + checkboxText: Res.MessageBoxDontShowAgainLabel, + isChecked: out dontShowAgain); + + // Update preference to not show again if checked + dynamoViewModel.Model.PreferenceSettings.HideCPython3Notifications = dontShowAgain; + + // First button (Yes) is "OK" + if (result == MessageBoxResult.Yes) + { + ws.HasShownCPythonNotification = true; + return false; + } + // Second button (No) is "Learn more" + else if (result == MessageBoxResult.No) + { + Process.Start(new ProcessStartInfo(Res.CPython3EngineUpgradeLearnMoreUri) { UseShellExecute = true }); + return true; + } + return false; + } + private void Selection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { dynamoViewModel.CopyCommand.RaiseCanExecuteChanged(); diff --git a/src/DynamoCoreWpf/Views/GuidedTour/RealTimeInfoWindow.xaml b/src/DynamoCoreWpf/Views/GuidedTour/RealTimeInfoWindow.xaml index 17e9801107a..c042f383223 100644 --- a/src/DynamoCoreWpf/Views/GuidedTour/RealTimeInfoWindow.xaml +++ b/src/DynamoCoreWpf/Views/GuidedTour/RealTimeInfoWindow.xaml @@ -69,16 +69,40 @@ StrokeThickness="2"/> - + + + + + + + + + + - - - - + diff --git a/src/DynamoCoreWpf/Views/Menu/PreferencesView.xaml.cs b/src/DynamoCoreWpf/Views/Menu/PreferencesView.xaml.cs index 8f609eee317..cf49f19e43f 100644 --- a/src/DynamoCoreWpf/Views/Menu/PreferencesView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Menu/PreferencesView.xaml.cs @@ -358,9 +358,9 @@ private void OnMoreInfoClicked(object sender, RoutedEventArgs e) } } - private void ReloadCPython_Click(object sender, RoutedEventArgs e) + private void ReloadPythonNet3_Click(object sender, RoutedEventArgs e) { - dynViewModel.Model.OnRequestPythonReset(PythonServices.PythonEngineManager.CPython3EngineName); + dynViewModel.Model.OnRequestPythonReset(PythonServices.PythonEngineManager.PythonNet3EngineName); } private void InstalledPackagesExpander_OnExpanded(object sender, RoutedEventArgs e) diff --git a/src/DynamoPackages/PackageManagerExtension.cs b/src/DynamoPackages/PackageManagerExtension.cs index 892f2b3d357..e3aa462802c 100644 --- a/src/DynamoPackages/PackageManagerExtension.cs +++ b/src/DynamoPackages/PackageManagerExtension.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Net.Http; using System.Reflection; +using Dynamo.Configuration; using Dynamo.Extensions; using Dynamo.Graph.Workspaces; using Dynamo.Interfaces; @@ -32,6 +33,7 @@ public class PackageManagerExtension : IExtension, ILogSource, IExtensionSource private ReadyParams ReadyParams; private Core.CustomNodeManager customNodeManager; + private PreferenceSettings prefSettings; /// /// Dictionary mapping a custom node functionID to the package that contains it. @@ -122,6 +124,7 @@ public void Dispose() /// public void Startup(StartupParams startupParams) { + prefSettings = startupParams.Preferences as PreferenceSettings; string url = DynamoUtilities.PathHelper.GetServiceBackendAddress(this, "packageManagerAddress"); OnMessageLogged(LogMessage.Info("Dynamo will use the package manager server at : " + url)); @@ -149,12 +152,6 @@ public void Startup(StartupParams startupParams) PackageLoader.RequestLoadNodeLibrary += RequestLoadNodeLibraryHandler; PackageLoader.RequestLoadCustomNodeDirectory += RequestLoadCustomNodeDirectoryHandler; - if (PythonServices.PythonEngineManager.Instance.AvailableEngines.Count == 0) - { - PythonServices.PythonEngineManager.Instance.LoadDefaultPythonEngine(AppDomain.CurrentDomain.GetAssemblies(). - FirstOrDefault(a => a != null && a.GetName().Name == PythonServices.PythonEngineManager.CPythonAssemblyName)); - } - PythonServices.PythonEngineManager.Instance.AvailableEngines.CollectionChanged += PythonEngineAdded; var dirBuilder = new PackageDirectoryBuilder( @@ -190,39 +187,38 @@ public void Startup(StartupParams startupParams) /// internal void PythonEngineAdded(object sender, NotifyCollectionChangedEventArgs e) { - if (e.Action == NotifyCollectionChangedAction.Add) + if (e.Action != NotifyCollectionChangedAction.Add || e.NewItems == null) return; + + try { - try - { - var assem = e.NewItems[0]?.GetType().Assembly; - if (assem == null) return; + var assem = e.NewItems[0]?.GetType().Assembly; + if (assem == null) return; - var assemLoc = assem.Location; - foreach (var pkg in PackageLoader.LocalPackages) + var assemLoc = assem.Location; + foreach (var pkg in PackageLoader.LocalPackages) + { + if (assemLoc.StartsWith(pkg.RootDirectory)) { - if (assemLoc.StartsWith(pkg.RootDirectory)) + if (NodePackageDictionary.ContainsKey(assem.FullName)) + { + var assemName = AssemblyName.GetAssemblyName(assem.Location); + OnMessageLogged(LogMessage.Info( + string.Format("{0} contains the python engine library {1}, which has already been loaded " + + "by another package. This may cause inconsistent results when determining which " + + "python engine the nodes are dependent on.", pkg.Name, assemName.Name) + )); + } + else { - if (NodePackageDictionary.ContainsKey(assem.FullName)) - { - var assemName = AssemblyName.GetAssemblyName(assem.Location); - OnMessageLogged(LogMessage.Info( - string.Format("{0} contains the python engine library {1}, which has already been loaded " + - "by another package. This may cause inconsistent results when determining which " + - "python engine the nodes are dependent on.", pkg.Name, assemName.Name) - )); - } - else - { - NodePackageDictionary[assem.FullName] = new List(); - } - NodePackageDictionary[assem.FullName].Add(new PackageInfo(pkg.Name, new Version(pkg.VersionName))); + NodePackageDictionary[assem.FullName] = new List(); } + NodePackageDictionary[assem.FullName].Add(new PackageInfo(pkg.Name, new Version(pkg.VersionName))); } } - catch(Exception ex) - { - OnMessageLogged(LogMessage.Info("Error occurred while recording python engine and package mapping. " + ex.Message)); - } + } + catch (Exception ex) + { + OnMessageLogged(LogMessage.Info("Error occurred while recording python engine and package mapping. " + ex.Message)); } } @@ -260,6 +256,25 @@ private void LoadPackages(IPreferences preferences, IPathManager pathManager) { Preferences = preferences, }); + EnsureDefaultPythonEngine(); + } + + private void EnsureDefaultPythonEngine() + { + if (prefSettings == null) return; + + var mgr = PythonServices.PythonEngineManager.Instance; + var current = prefSettings.DefaultPythonEngine; + var isValid = !string.IsNullOrEmpty(current) && mgr.AvailableEngines.Any(x => x.Name == current); + if (isValid) return; + + var preferred = mgr.AvailableEngines.FirstOrDefault(x => x.Name == PythonServices.PythonEngineManager.PythonNet3EngineName) + ?? mgr.AvailableEngines.FirstOrDefault(); + + if (preferred != null && preferred.Name != current) + { + prefSettings.DefaultPythonEngine = preferred.Name; + } } private void OnMessageLogged(ILogMessage msg) diff --git a/src/Libraries/DSCPython/CPythonEvaluator.cs b/src/Libraries/DSCPython/CPythonEvaluator.cs deleted file mode 100644 index 4a5de711592..00000000000 --- a/src/Libraries/DSCPython/CPythonEvaluator.cs +++ /dev/null @@ -1,736 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using Autodesk.DesignScript.Runtime; -using DSCPython.Encoders; -using Dynamo.Events; -using Dynamo.Logging; -using Dynamo.PythonServices.EventHandlers; -using Dynamo.Session; -using Dynamo.Utilities; -using Python.Runtime; - -namespace DSCPython -{ - /// - /// Used to compare DynamoCPythonHandles by their PythonIDs. - /// - internal class DynamoCPythonHandleComparer : IEqualityComparer - { - - public bool Equals(DynamoCPythonHandle x, DynamoCPythonHandle y) - { - return x.PythonObjectID.Equals(y.PythonObjectID); - } - - public int GetHashCode(DynamoCPythonHandle obj) - { - return obj.PythonObjectID.GetHashCode(); - } - } - - /// - /// This class wraps a PythonNet.PyObj and performs - /// disposal tasks to make sure the underlying object is removed from - /// the shared global scope between all CPython scopes. - /// If you construct an instance of this class manually or - /// as a consequence of using the CPythonEvaluator.Evaluate method, an instance - /// of this class is constructed, and is not returned to the DSVM (graph context) - /// then make sure to call Dispose when you are done with the instance. - /// - [IsVisibleInDynamoLibrary(false)] - internal class DynamoCPythonHandle : IDisposable - { - /// - /// A static map of DynamoCPythonHandle counts, is used to avoid removing the underlying python objects from the - /// global scope while there are still handles referencing them. - /// - internal static Dictionary HandleCountMap = new Dictionary(new DynamoCPythonHandleComparer()); - - /// - /// A unique ID that identifies this python object. It's as a lookup - /// symbol within the global scope to find this python object instance. - /// - internal IntPtr PythonObjectID { get; set; } - - public DynamoCPythonHandle(IntPtr id) - { - PythonObjectID = id; - if (HandleCountMap.ContainsKey(this)) - { - HandleCountMap[this] = HandleCountMap[this] + 1; - } - else - { - HandleCountMap.Add(this, 1); - } - } - - public override string ToString() - { - IntPtr gs = PythonEngine.AcquireLock(); - try - { - using (Py.GIL()) - { - var scope = PyScopeManager.Global.Get(CPythonEvaluator.globalScopeName); - var pyobj = scope.Get(PythonObjectID.ToString()); - return pyobj.ToString(); - } - } - catch (Exception e) - { - CPythonEvaluator.DynamoLogger?.Log($"error getting string rep of pyobj {this.PythonObjectID} {e.Message}"); - return this.PythonObjectID.ToString(); - } - finally - { - PythonEngine.ReleaseLock(gs); - } - } - - /// - /// When this handle goes out of scope - /// we should remove the pythonObject from the globalScope. - /// In most cases the DSVM will call this. - /// - public void Dispose() - { - //key doesn't exist. - if (!HandleCountMap.ContainsKey(this)) - { - return; - } - //there are more than 1 reference left, don't dispose. - //decrement refs - if (HandleCountMap[this] > 1) - { - HandleCountMap[this] = HandleCountMap[this] - 1; - return; - } - - IntPtr gs = PythonEngine.AcquireLock(); - try - { - using (Py.GIL()) - { - PyScopeManager.Global.Get(CPythonEvaluator.globalScopeName).Remove(PythonObjectID.ToString()); - HandleCountMap.Remove(this); - } - } - catch (Exception e) - { - CPythonEvaluator.DynamoLogger?.Log($"error removing python object from global scope {e.Message}"); - } - finally - { - PythonEngine.ReleaseLock(gs); - } - } - } - - - /// - /// Evaluates a Python script in the Dynamo context. - /// - [IsVisibleInDynamoLibrary(false)] - public class CPythonEvaluator : Dynamo.PythonServices.PythonEngine - { - private const string DynamoSkipAttributeName = "__dynamoskipconversion__"; - private const string DynamoPrintFuncName = "__dynamoprint__"; - private const string NodeName = "__dynamonodename__"; - internal static readonly string globalScopeName = "global"; - - private static PyScope globalScope; - private static DynamoLogger dynamoLogger; - private static string path; - - internal static DynamoLogger DynamoLogger { - get - { // Session is null when running unit tests. - if (ExecutionEvents.ActiveSession != null) - { - dynamoLogger = ExecutionEvents.ActiveSession.GetParameterValue(ParameterKeys.Logger) as DynamoLogger; - return dynamoLogger; - } - return dynamoLogger; - } - } - - /// - /// Use Lazy<PythonEngineManager> to make sure the Singleton class is only initialized once - /// - private static readonly Lazy - lazy = - new Lazy - (() => new CPythonEvaluator()); - - /// - /// The actual instance stored in the Singleton class - /// - internal static CPythonEvaluator Instance { get { return lazy.Value; } } - - static CPythonEvaluator() - { - InitializeEncoders(); - Dynamo.Models.DynamoModel.RequestPythonReset += RequestPythonResetHandler; - } - - public override string Name => Dynamo.PythonServices.PythonEngineManager.CPython3EngineName; - - internal static void RequestPythonResetHandler(string pythonEngine) - { - //check if python engine request is for this engine, and engine is currently started - if (PythonEngine.IsInitialized && pythonEngine == Instance.Name) - { - DynamoLogger?.Log("attempting reload of cpython3 modules", LogLevel.Console); - using (Py.GIL()) - { - //the following is inspired by: - //https://github.com/ipython/ipython/blob/master/IPython/extensions/autoreload.py - var global = PyScopeManager.Global.Get(CPythonEvaluator.globalScopeName); - global?.Exec(@"import sys -import importlib -import importlib.util -import os -## Reloading sys, __main__, builtins and other key modules is not recommended. -## don't reload modules without file attributes -def should_reload(module): - if not hasattr(module, '__file__') or module.__file__ is None: - return None -## don't reload modules that are currently running ie __main__, __mp_main__ is renamed by multiprocessing module. - if getattr(module, '__name__', None) in [None, '__mp_main__', '__main__']: - # we cannot reload(__main__) or reload(__mp_main__) - return None - - filename = module.__file__ - path, ext = os.path.splitext(filename) -## only reload .py files. - if ext.lower() == '.py': - py_filename = filename - else: - try: - py_filename = importlib.util.source_from_cache(filename) - except ValueError: - return None - return py_filename - -## copy sys.modules so it's not modified during reload. -for modname,mod in sys.modules.copy().items(): - print('considering', modname) - file = should_reload(mod) - if file is None: - continue - print('reloading', modname) - try: - importlib.reload(mod) - except Exception as inst: - print('failed to reload', modname, inst) - -"); - } - Analytics.TrackEvent( - Dynamo.Logging.Actions.Start, - Dynamo.Logging.Categories.PythonOperations, - "CPythonReset"); - } - } - - /// - /// Executes a Python script with custom variable names. Script may be a string - /// read from a file, for example. Pass a list of names (matching the variable - /// names in the script) to bindingNames and pass a corresponding list of values - /// to bindingValues. - /// - /// Python script as a string. - /// Names of values referenced in Python script. - /// Values referenced in Python script. - public override object Evaluate( - string code, - IList bindingNames, - [ArbitraryDimensionArrayImport] IList bindingValues) - { - var evaluationSuccess = true; - if (code == null) - { - return null; - } - - InstallPython(); - if (!PythonEngine.IsInitialized) - { - PythonEngine.Initialize(); - PythonEngine.BeginAllowThreads(); - - using (Py.GIL()) - using (PyScope scope = Py.CreateScope()) - { - scope.Exec("import sys" + Environment.NewLine + "path = str(sys.path)"); - path = scope.Get("path"); - } - } - - using (Py.GIL()) - { - globalScope ??= CreateGlobalScope(); - using (PyScope scope = Py.CreateScope()) - { - if (path is not null) - { - // Reset the 'sys.path' value to the default python paths on node evaluation. See https://github.com/DynamoDS/Dynamo/pull/10977. - var pythonNodeSetupCode = "import sys" + Environment.NewLine + $"sys.path = {path}"; - scope.Exec(pythonNodeSetupCode); - } - - ProcessAdditionalBindings(scope, bindingNames, bindingValues); - - int amt = Math.Min(bindingNames.Count, bindingValues.Count); - - for (int i = 0; i < amt; i++) - { - scope.Set((string)bindingNames[i], InputMarshaler.Marshal(bindingValues[i]).ToPython()); - } - - try - { - OnEvaluationBegin(scope, code, bindingValues); - scope.Exec(code); - var result = scope.Contains("OUT") ? scope.Get("OUT") : null; - - return OutputMarshaler.Marshal(result); - } - catch (Exception e) - { - evaluationSuccess = false; - var traceBack = GetTraceBack(e); - if (!string.IsNullOrEmpty(traceBack)) - { - // Throw a new error including trace back info added to the message - throw new InvalidOperationException($"{e.Message} {traceBack}", e); - } - else - { -#pragma warning disable CA2200 // Rethrow to preserve stack details - throw e; -#pragma warning restore CA2200 // Rethrow to preserve stack details - } - } - finally - { - OnEvaluationEnd(evaluationSuccess, scope, code, bindingValues); - } - } - } - } - - public static object EvaluatePythonScript( - string code, - IList bindingNames, - [ArbitraryDimensionArrayImport] IList bindingValues) - { - return Instance.Evaluate(code, bindingNames, bindingValues); - } - - private static bool isPythonInstalled = false; - /// - /// Makes sure Python is installed on the system and it's location added to the path. - /// NOTE: Calling SetupPython multiple times will add the install location to the path many times, - /// potentially causing the environment variable to overflow. - /// - internal static void InstallPython() - { - if (!isPythonInstalled) - { - Python.Included.Installer.SetupPythonSync(); - isPythonInstalled = true; - } - } - - /// - /// Creates and initializes the global Python scope. - /// - private static PyScope CreateGlobalScope() - { - var scope = Py.CreateScope(globalScopeName); - // Allows discoverability of modules by inspecting their attributes - scope.Exec(@" -import clr -clr.setPreload(True) -"); - - return scope; - } - - /// - /// Processes additional bindings that are not actual inputs. - /// Currently, only the node name is received in this way. - /// - /// Python scope where execution will occur - /// List of binding names received for evaluation - /// List of binding values received for evaluation - private static void ProcessAdditionalBindings(PyScope scope, IList bindingNames, IList bindingValues) - { - const string NodeNameInput = "Name"; - string nodeName; - if (bindingNames.Count == 0 || !bindingNames[0].Equals(NodeNameInput)) - { - // Defensive code to fallback in case the additional binding is not there, like - // when the evaluator is called directly in unit tests. - nodeName = "USER"; - } - else - { - bindingNames.RemoveAt(0); - nodeName = (string)bindingValues[0]; - bindingValues.RemoveAt(0); - } - - // Session is null when running unit tests. - if (ExecutionEvents.ActiveSession != null) - { - var logger = DynamoLogger; - Action logFunction = msg => logger.Log($"{nodeName}: {msg}", LogLevel.ConsoleOnly); - scope.Set(DynamoPrintFuncName, logFunction.ToPython()); - scope.Exec(RedirectPrint()); - } - } - - private static string RedirectPrint() - { - return string.Format(@" -import sys - -class DynamoStdOut: - def __init__(self, log_func): - self.text = '' - self.log_func = log_func - def write(self, text): - if text == '\n': - self.log_func(self.text) - self.text = '' - else: - self.text += text -sys.stdout = DynamoStdOut({0}) -", DynamoPrintFuncName); - } - - /// - /// Registers custom encoders and decoders with the Python.NET runtime - /// - private static void InitializeEncoders() - { - var shared = new object[] { new BigIntegerEncoderDecoder(), new ListEncoderDecoder() }; - var encoders = shared.Cast().ToArray(); - var decoders = shared.Cast().Concat(new IPyObjectDecoder[] - { - new DictionaryDecoder() - }).ToArray(); - Array.ForEach(encoders, e => PyObjectConversions.RegisterEncoder(e)); - Array.ForEach(decoders, d => PyObjectConversions.RegisterDecoder(d)); - } - - /// - /// Gets the trace back message from the exception, if it is a PythonException. - /// - /// Exception to inspect - /// Trace back message - private static string GetTraceBack(Exception e) - { - var pythonExc = e as PythonException; - if (!(e is PythonException)) - { - return null; - } - - // Return the value of the trace back field (private) - var field = typeof(PythonException).GetField("_tb", BindingFlags.NonPublic | BindingFlags.Instance); - if (field == null) - { - throw new NotSupportedException(Properties.Resources.InternalErrorTraceBackInfo); - } - return field.GetValue(pythonExc).ToString(); - } - - #region Marshalling - - /// - /// Add additional data marshalers to handle host data. - /// - [SupressImportIntoVM] - internal override void RegisterHostDataMarshalers() - { - DataMarshaler dataMarshalerToUse = HostDataMarshaler as DataMarshaler; - dataMarshalerToUse?.RegisterMarshaler((PyObject pyObj) => - { - try - { - using (Py.GIL()) - { - if (PyDict.IsDictType(pyObj)) - { - using (var pyDict = new PyDict(pyObj)) - { - var dict = new PyDict(); - foreach (PyObject item in pyDict.Items()) - { - dict.SetItem( - ConverterExtension.ToPython(dataMarshalerToUse.Marshal(item.GetItem(0))), - ConverterExtension.ToPython(dataMarshalerToUse.Marshal(item.GetItem(1))) - ); - } - return dict; - } - } - var unmarshalled = pyObj.AsManagedObject(typeof(object)); - - // Avoid calling this marshaler infinitely. - if (unmarshalled is PyObject) - { - return unmarshalled; - } - - return dataMarshalerToUse.Marshal(unmarshalled); - } - } - catch (Exception e) - { - DynamoLogger?.Log($"error marshaling python object {pyObj.Handle} {e.Message}"); - return pyObj; - } - }); - } - - /// - /// Data Marshaler for all data coming into a Python node. - /// - [SupressImportIntoVM] - public override object InputDataMarshaler - { - get - { - if (inputMarshaler == null) - { - inputMarshaler = new DataMarshaler(); - inputMarshaler.RegisterMarshaler( - delegate (IList lst) - { - var pyList = new PyList(); - foreach (var item in lst.Cast().Select(inputMarshaler.Marshal)) - { - pyList.Append(item.ToPython()); - } - return pyList; - }); - inputMarshaler.RegisterMarshaler( - delegate (DesignScript.Builtin.Dictionary dict) - { - var pyDict = new PyDict(); - foreach (var key in dict.Keys) - { - pyDict.SetItem(inputMarshaler.Marshal(key).ToPython(), inputMarshaler.Marshal(dict.ValueAtKey(key)).ToPython()); - } - return pyDict; - }); - - inputMarshaler.RegisterMarshaler( - delegate (DynamoCPythonHandle handle) - { - var scope = PyScopeManager.Global.Get(globalScopeName); - return scope.Get(handle.PythonObjectID.ToString()); - }); - } - return inputMarshaler; - } - } - - /// - /// Data Marshaler for all data coming into a Python node. - /// - [SupressImportIntoVM] - public static DataMarshaler InputMarshaler => Instance.InputDataMarshaler as DataMarshaler; - - /// - /// Data Marshaler for all data coming out of a Python node. - /// - [SupressImportIntoVM] - public override object OutputDataMarshaler - { - get - { - if (outputMarshaler == null) - { - outputMarshaler = new DataMarshaler(); - outputMarshaler.RegisterMarshaler( - delegate (PyObject pyObj) - { - // First, check if we are dealing with a wrapped .NET object. - // This simplifies the cases that come afterwards, as wrapped - // .NET collections pass some Python checks but not others. - var clrObj = pyObj.GetManagedObject(); - if (clrObj != null) - { - return outputMarshaler.Marshal(clrObj); - } - - if (IsMarkedToSkipConversion(pyObj)) - { - return GetDynamoCPythonHandle(pyObj); - } - - // Dictionaries are iterable, so they should come first - if (PyDict.IsDictType(pyObj)) - { - using (var pyDict = new PyDict(pyObj)) - { - var dict = new Dictionary(); - foreach (PyObject item in pyDict.Items()) - { - dict.Add( - outputMarshaler.Marshal(item.GetItem(0)), - outputMarshaler.Marshal(item.GetItem(1)) - ); - } - return dict; - } - } - // Other iterables should become lists, except for strings - if (PyIter.IsIterable(pyObj) && !PyString.IsStringType(pyObj)) - { - using (var pyList = PyList.AsList(pyObj)) - { - var list = new List(); - foreach (PyObject item in pyList) - { - list.Add(outputMarshaler.Marshal(item)); - } - return list; - } - } - // Special case for big long values: decode them as BigInteger - if (PyLong.IsLongType(pyObj)) - { - using (var pyLong = PyLong.AsLong(pyObj)) - { - try - { - return pyLong.ToInt64(); - } - catch (PythonException exc) when (exc.Message.StartsWith("OverflowError")) - { - return pyLong.ToBigInteger(); - } - } - } - // Default handling for other Python objects - var unmarshalled = pyObj.AsManagedObject(typeof(object)); - if (unmarshalled is PyObject) - { - using (unmarshalled as PyObject) - { - if (unmarshalled.Equals(pyObj)) - { - return GetDynamoCPythonHandle(pyObj); - } - else - { - return outputMarshaler.Marshal(unmarshalled); - } - } - } - - return outputMarshaler.Marshal(unmarshalled); - }); - } - return outputMarshaler; - } - } - - /// - /// Data Marshaler for all data coming out of a Python node. - /// - [SupressImportIntoVM] - public static DataMarshaler OutputMarshaler => Instance.OutputDataMarshaler as DataMarshaler; - - private static DynamoCPythonHandle GetDynamoCPythonHandle(PyObject pyObj) - { - var globalScope = PyScopeManager.Global.Get(globalScopeName); - globalScope.Set(pyObj.Handle.ToString(), pyObj); - return new DynamoCPythonHandle(pyObj.Handle); - } - - private static bool IsMarkedToSkipConversion(PyObject pyObj) - { - return pyObj.HasAttr(DynamoSkipAttributeName); - } - - private DataMarshaler inputMarshaler; - private DataMarshaler outputMarshaler; - - #endregion - - #region Evaluation events - - /// - /// Emitted immediately before execution begins - /// - [SupressImportIntoVM] - public override event EvaluationStartedEventHandler EvaluationStarted; - - /// - /// Emitted immediately after execution ends or fails - /// - [SupressImportIntoVM] - public override event EvaluationFinishedEventHandler EvaluationFinished; - - /// - /// Called immediately before evaluation starts - /// - /// The scope in which the code is executed - /// The code to be evaluated - /// The binding values - these are already added to the scope when called - private void OnEvaluationBegin(PyScope scope, - string code, - IList bindingValues) - { - if (EvaluationStarted != null) - { - EvaluationStarted(code, bindingValues, (n, v) => { scope.Set(n, InputMarshaler.Marshal(v).ToPython()); }); - Analytics.TrackEvent( - Dynamo.Logging.Actions.Start, - Dynamo.Logging.Categories.PythonOperations, - "CPythonEvaluation"); - } - } - - /// - /// Called when the evaluation has completed successfully or failed - /// - /// Whether the evaluation succeeded or not - /// The scope in which the code is executed - /// The code to that was evaluated - /// The binding values - these are already added to the scope when called - private void OnEvaluationEnd(bool isSuccessful, - PyScope scope, - string code, - IList bindingValues) - { - if (EvaluationFinished != null) - { - EvaluationFinished(isSuccessful ? Dynamo.PythonServices.EvaluationState.Success : Dynamo.PythonServices.EvaluationState.Failed, - code, bindingValues, (n) => { - return OutputMarshaler.Marshal(scope.Get(n)); - }); - Analytics.TrackEvent( - Dynamo.Logging.Actions.End, - Dynamo.Logging.Categories.PythonOperations, - "CPythonEvaluation"); - } - } - - #endregion - - } -} diff --git a/src/Libraries/DSCPython/DSCPython.csproj b/src/Libraries/DSCPython/DSCPython.csproj deleted file mode 100644 index 2f9a37109f9..00000000000 --- a/src/Libraries/DSCPython/DSCPython.csproj +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - {F1541C2D-80A9-4FE7-8D9E-75A8B9FF3479} - Library - Properties - DSCPython - DSCPython - - - MSB3539;CS1591;NUnit2005;NUnit2007;CS0618;CS0612;CS0672 - - - - - - - False - ..\..\..\extern\Python\Python.Included.dll - - - False - ..\..\..\extern\Python\Python.Included.SciPy.dll - - - False - ..\..\..\extern\Python\Python.Runtime.dll - - - - - {7858FA8C-475F-4B8E-B468-1F8200778CF8} - DynamoCore - - - {b5f435cb-0d8a-40b1-a4f7-5ecb3ce792a9} - DynamoUtilities - False - - - {ef879a10-041d-4c68-83e7-3192685f1bae} - DynamoServices - False - - - {c0d6dee5-5532-4345-9c66-4c00d7fdb8be} - DesignScriptBuiltin - False - - - - - True - True - Resources.resx - - - True - True - Resources.en-US.resx - - - - - ResXFileCodeGenerator - Resources.Designer.cs - - - ResXFileCodeGenerator - Resources.en-US.Designer.cs - - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/DSCPythonCodeCompletionProviderCore.cs b/src/Libraries/DSCPython/DSCPythonCodeCompletionProviderCore.cs deleted file mode 100644 index ead30d8e3d8..00000000000 --- a/src/Libraries/DSCPython/DSCPythonCodeCompletionProviderCore.cs +++ /dev/null @@ -1,494 +0,0 @@ -using Autodesk.DesignScript.Interfaces; -using Dynamo.Logging; -using Dynamo.PythonServices; -using Python.Runtime; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using PythonEngine = Python.Runtime.PythonEngine; - -namespace DSCPython -{ - internal class DSCPythonCodeCompletionProviderCore : PythonCodeCompletionProviderCommon, ILogSource, IDisposable - { - #region Private members - // Get clr type if name is an instance of type and if name is not a builtin python type. - // Builtin python types might have a corresponding clr type but we pythonnet only knows about the python type. - internal static readonly string clrTypeLookup = "clr.GetClrType({0}) if isinstance({0}, type) and (\"{0}\" not in __builtins__) else None"; - - /// - /// The engine used for autocompletion. This essentially keeps - /// track of the state of the editor, allowing access to variable types and - /// imported symbols. - /// - private PyScope scope; - - private string uniquePythonScopeName = "uniqueScope"; - private static string globalScopeName = "cPythonCompletionGlobal"; - - // Dictionary basic of Python types to instances of those types - private Dictionary basicPyObjects; - - /// - /// The scope used by the engine. This is where all the loaded symbols - /// are stored. It's essentially an environment dictionary. - /// - internal PyScope Scope - { - get { return scope; } - set { scope = (PyScope)value; } - } - - private static PyScope GlobalScope; - - private PyScope CreateUniquePythonScope() - { - PyScopeManager.Global.TryGet(uniquePythonScopeName, out PyScope Scope); - - if (Scope == null) - { - Scope = Py.CreateScope(uniquePythonScopeName); - Scope.Exec(@" -import clr -import sys -"); - } - - return Scope; - } - - private static PyScope CreateGlobalScope() - { - var scope = Py.CreateScope(globalScopeName); - // Allows discoverability of modules by inspecting their attributes - scope.Exec(@" -import clr -clr.setPreload(True) -"); - - return scope; - } - - private object ExecutePythonScriptCode(string code) - { - DSCPython.CPythonEvaluator.InstallPython(); - - if (!PythonEngine.IsInitialized) - { - PythonEngine.Initialize(); - PythonEngine.BeginAllowThreads(); - } - - using (Py.GIL()) - { - var result = Scope.Eval(code); - return CPythonEvaluator.OutputMarshaler.Marshal(result); - } - } - - public new IEnumerable> EnumerateMembers(Type type, string name) - { - return base.EnumerateMembers(type, name); - } - - /// - /// List all of the members in a PythonObject. - /// This method calls into Python objects and thus needs to be wrappd in a GIL block. - /// - /// A reference to the module - /// The name of the module - /// A list of completion data for the module - private IEnumerable> EnumerateMembers(object pyObject, string name) - { - var items = new List>(); - var d = pyObject as PyObject; - if (d == null) - { - return items; - } - - bool isCLRType = false; - try - { - // Usefull when parsing CLR namespaces (ex. System.Collections.) - isCLRType = d.GetAttr("__class__").ToString().Contains("CLR"); - } - catch { } - - foreach (var member in d.Dir()) - { - try - { - var completionType = ExternalCodeCompletionType.Field; - - var memberName = member.ToString(); - var attr = d.GetAttr(memberName).ToString(); - if (isCLRType && ( - memberName.StartsWith("__") && memberName.EndsWith("__"))) - {//Ignone python specific members when dealing with wrapped .NET objects - continue; - } - - if (attr.IndexOf(method, StringComparison.OrdinalIgnoreCase) >= 0 || - attr.IndexOf(inBuiltMethod, StringComparison.OrdinalIgnoreCase) >= 0 || - attr.IndexOf("function", StringComparison.OrdinalIgnoreCase) >= 0) - { - completionType = ExternalCodeCompletionType.Method; - } - else if (attr.IndexOf("class", StringComparison.OrdinalIgnoreCase) >= 0) - { - completionType = ExternalCodeCompletionType.Class; - } - else if (attr.IndexOf("namespace", StringComparison.OrdinalIgnoreCase) >= 0 || - attr.IndexOf("module", StringComparison.OrdinalIgnoreCase) >= 0) - { - completionType = ExternalCodeCompletionType.Namespace; - } - - items.Add(Tuple.Create(member.ToString(), name, false, completionType)); - } - catch (Exception ex) - { - Log(ex.ToString()); - } - } - - return items; - } - - /// - /// Lookup a variable in the python environment - /// - /// A name for a type, possibly delimited by periods. - /// The Python object - private PyObject LookupObject(string name) - { - var periodIndex = name.IndexOf('.'); - using (Py.GIL()) - { - if (periodIndex == -1) - { - if (Scope.TryGet(name, out PyObject varOutput) && varOutput != null) - { - return varOutput; - } - } - - try - { - // There is an issue with calling Dir() on nested PyObjects (not all members are discovered) - // As a workaround we can retrieve the PyObject by evaluating directly in Python - return Scope.Eval(string.Format("{0}", name)); - } - catch - { - return null; - } - } - } - #endregion - - #region PythonCodeCompletionProviderCommon public methods implementations - - /// - /// Generate completion data for the specified text, while import the given types into the - /// scope and discovering variable assignments. - /// - /// The code to parse - /// Determines if the entire namespace should be used - /// Return a list of IExternalCodeCompletionData - public override IExternalCodeCompletionData[] GetCompletionData(string code, bool expand = false) - { - IEnumerable items = new List(); - - if (!PythonEngine.IsInitialized) - { - PythonEngine.Initialize(); - PythonEngine.BeginAllowThreads(); - } - - try - { - using (Py.GIL()) - { - if (code.Contains("\"\"\"")) - { - code = StripDocStrings(code); - } - - UpdateImportedTypes(code); - UpdateVariableTypes(code); // Possibly use hindley-milner in the future - - // If expand param is true use the entire namespace from the line of code - // Else just return the last name of the namespace - string name = expand ? GetLastNameSpace(code) : GetLastName(code); - if (!String.IsNullOrEmpty(name)) - { - try - { - // Attempt to get type using naming - Type type = expand ? TryGetTypeFromFullName(name) : TryGetType(name); - // CLR type - if (type != null) - { - items = EnumerateMembers(type, name).Select(x => new PythonCodeCompletionDataCore(x.Item1, x.Item2, x.Item3, x.Item4, this)); - } - // Variable assignment types - else if (VariableTypes.TryGetValue(name, out type)) - { - if (basicPyObjects.TryGetValue(type, out PyObject basicObj)) - { - items = EnumerateMembers(basicObj, name).Select(x => new PythonCodeCompletionDataCore(x.Item1, x.Item2, x.Item3, x.Item4, this)); - } - else - { - items = EnumerateMembers(type, name).Select(x => new PythonCodeCompletionDataCore(x.Item1, x.Item2, x.Item3, x.Item4, this)); - } - } - else - { - // Try to find the corresponding PyObject from the python environment - // Most types should be successfully retrieved at this stage - var pyObj = LookupObject(name); - if (pyObj != null) - { - items = EnumerateMembers(pyObj, name).Select(x => new PythonCodeCompletionDataCore(x.Item1, x.Item2, x.Item3, x.Item4, this)); - } - } - } - catch (Exception ex) - { - Log(ex.ToString()); - } - } - } - } - catch {} - - // If unable to find matching results and expand was set to false, - // try again using the full namespace (set expand to true) - if (!items.Any() && !expand) - { - return GetCompletionData(code, true); - } - - return items.ToArray(); - } - - protected override object GetDescriptionObject(string docCommand) - { - try - { - return ExecutePythonScriptCode(docCommand); - } - catch - { - //This empty catch block is intentional- - //because we are using a python engine to evaluate the completions - //but this engine has not actually loaded the types, it will throw lots of exceptions - //we wish to suppress. - } - - return null; - } - - /// - /// Used to determine if this IExternalCodeCompletionProviderCore can provide completions for the given engine. - /// - /// - /// - public override bool IsSupportedEngine(string engineName) - { - if (engineName == PythonEngineManager.CPython3EngineName) - { - return true; - } - return false; - } - - /// - /// Used to load initialize libraries and types that should be available by default. - /// - /// - public override void Initialize(string dynamoCorePath) - {} - #endregion - - #region PythonCodeCompletionProviderCommon protected methods implementations - protected override object EvaluateScript(string script, PythonScriptType evalType) - { - using (Py.GIL()) - { - switch (evalType) - { - case PythonScriptType.Expression: - var result = Scope.Eval(script); - return CPythonEvaluator.OutputMarshaler.Marshal(result); - default: - Scope.Exec(script); - return null; - } - } - } - - protected override void LogError(string msg) - { - Log(msg); - } - - protected internal override bool ScopeHasVariable(string name) - { - using (Py.GIL()) - { - return Scope.Contains(name); - } - } - - protected override Type GetCLRType(string name) - { - using (Py.GIL()) - { - var result = Scope.Eval(String.Format(clrTypeLookup, name)); - return result?.GetManagedObject() as Type;//Get the .Net wrapped object - } - } - #endregion - - #region constructor - public DSCPythonCodeCompletionProviderCore() - { - VariableTypes = new Dictionary(); - ImportedTypes = new Dictionary(); - ClrModules = new HashSet(); - BadStatements = new Dictionary(); - Guid pythonScopeGUID = Guid.NewGuid(); - uniquePythonScopeName += pythonScopeGUID.ToString(); - - // Special case for python variables defined as null - ImportedTypes["None"] = null; - - BasicVariableTypes = new List>(); - - BasicVariableTypes.Add(Tuple.Create(STRING_VARIABLE, typeof(PyString))); - BasicVariableTypes.Add(Tuple.Create(DOUBLE_VARIABLE, typeof(PyFloat))); - BasicVariableTypes.Add(Tuple.Create(INT_VARIABLE, typeof(PyInt))); - BasicVariableTypes.Add(Tuple.Create(LIST_VARIABLE, typeof(PyList))); - BasicVariableTypes.Add(Tuple.Create(DICT_VARIABLE, typeof(PyDict))); - - DSCPython.CPythonEvaluator.InstallPython(); - - if (!PythonEngine.IsInitialized) - { - PythonEngine.Initialize(); - PythonEngine.BeginAllowThreads(); - } - - try - { - using (Py.GIL()) - { - if (GlobalScope == null) - { - GlobalScope = CreateGlobalScope(); - } - - if (Scope == null) - { - Scope = CreateUniquePythonScope(); - } - - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - - // Determine if the Revit API is available in the given context - if (assemblies.Any(x => x.GetName().Name == "RevitAPI")) - { - // Try to load Revit Type for autocomplete - try - { - var revitImports = - "import clr\nclr.AddReference('RevitAPI')\nclr.AddReference('RevitAPIUI')\nfrom Autodesk.Revit.DB import *\nimport Autodesk\n"; - - Scope.Exec(revitImports); - - ClrModules.Add("RevitAPI"); - ClrModules.Add("RevitAPIUI"); - } - catch - { - Log("Failed to load Revit types for autocomplete. Python autocomplete will not see Autodesk namespace types."); - } - } - - // Determine if the ProtoGeometry is available in the given context - if (assemblies.Any(x => x.GetName().Name == "ProtoGeometry")) - { - // Try to load ProtoGeometry Type for autocomplete - try - { - var libGImports = - "import clr\nclr.AddReference('ProtoGeometry')\nfrom Autodesk.DesignScript.Geometry import *\n"; - - Scope.Exec(libGImports); - ClrModules.Add("ProtoGeometry"); - } - catch (Exception e) - { - Log(e.ToString()); - Log("Failed to load ProtoGeometry types for autocomplete. Python autocomplete will not see Autodesk namespace types."); - } - } - - // PythonNet evaluates basic types as Python native types: - // Ex: a = "" - // type(a) will have the value {class str} and not the clr System.String - // - // Populate the basic types after python is initialized - // These instance types will correspond to Python basic types (no clr) - // ex. PyString("") => Python's {class str} - // PyInt(0) => Python's {class int} - basicPyObjects = new Dictionary(); - basicPyObjects[typeof(PyString)] = new PyString(""); - basicPyObjects[typeof(PyFloat)] = new PyFloat(0); - basicPyObjects[typeof(PyInt)] = new PyInt(0); - basicPyObjects[typeof(PyList)] = new PyList(); - basicPyObjects[typeof(PyDict)] = new PyDict(); - } - } - catch {} - } - #endregion - - #region ILogSource Implementation - /// - /// Raise this event to request loggers log this message. - /// - public event Action MessageLogged; - - internal void Log(string message) - { - MessageLogged?.Invoke(LogMessage.Info(message)); - } - - public void Dispose() - { - if (Scope != null) - { - if (!PythonEngine.IsInitialized) - { - PythonEngine.Initialize(); - PythonEngine.BeginAllowThreads(); - } - try - { - using (Py.GIL()) - { - Scope.Dispose(); - } - } - catch {} - } - } - #endregion - } -} \ No newline at end of file diff --git a/src/Libraries/DSCPython/Encoders/BigIntegerEncoderDecoder.cs b/src/Libraries/DSCPython/Encoders/BigIntegerEncoderDecoder.cs deleted file mode 100644 index 3a811f27bc0..00000000000 --- a/src/Libraries/DSCPython/Encoders/BigIntegerEncoderDecoder.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Numerics; -using Python.Runtime; - -namespace DSCPython.Encoders -{ - internal class BigIntegerEncoderDecoder : IPyObjectEncoder, IPyObjectDecoder - { - public bool CanDecode(PyObject objectType, Type targetType) - { - return targetType == typeof(BigInteger); - } - - public bool CanEncode(Type type) - { - return type == typeof(BigInteger); - } - - public bool TryDecode(PyObject pyObj, out T value) - { - if (!PyLong.IsLongType(pyObj)) - { - value = default; - return false; - } - - using (var pyLong = PyLong.AsLong(pyObj)) - { - value = (T)(object)pyLong.ToBigInteger(); - return true; - } - } - - public PyObject TryEncode(object value) - { - return new PyLong(value.ToString()); - } - } -} diff --git a/src/Libraries/DSCPython/Encoders/DictionaryDecoder.cs b/src/Libraries/DSCPython/Encoders/DictionaryDecoder.cs deleted file mode 100644 index dc997f36cd2..00000000000 --- a/src/Libraries/DSCPython/Encoders/DictionaryDecoder.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Dynamo.Utilities; -using Python.Runtime; - -namespace DSCPython.Encoders -{ - internal class DictionaryDecoder : IPyObjectDecoder - { - private static readonly Type[] decodableTypes = new Type[] - { - typeof(IDictionary<,>), typeof(Dictionary<,>), - typeof(IDictionary), typeof(Hashtable) - }; - - public bool CanDecode(PyObject objectType, Type targetType) - { - if (targetType.IsGenericType) - { - targetType = targetType.GetGenericTypeDefinition(); - } - return decodableTypes.IndexOf(targetType) >= 0; - } - - public bool TryDecode(PyObject pyObj, out T value) - { - if (!PyDict.IsDictType(pyObj)) - { - value = default; - return false; - } - using (var pyDict = new PyDict(pyObj)) - { - if (typeof(T).IsGenericType) - { - value = pyDict.ToDictionary(); - } - else - { - value = (T)pyDict.ToDictionary(); - } - return true; - } - } - } -} diff --git a/src/Libraries/DSCPython/Encoders/ListEncodeDecoder.cs b/src/Libraries/DSCPython/Encoders/ListEncodeDecoder.cs deleted file mode 100644 index 9572837615e..00000000000 --- a/src/Libraries/DSCPython/Encoders/ListEncodeDecoder.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using Dynamo.Utilities; -using Python.Runtime; - -namespace DSCPython.Encoders -{ - internal class ListEncoderDecoder : IPyObjectEncoder, IPyObjectDecoder - { - private static readonly Type[] decodableTypes = new Type[] - { - typeof(IList), typeof(ArrayList), - typeof(IList<>), typeof(List<>), - typeof(IEnumerable), typeof(IEnumerable<>) - }; - - public bool CanDecode(PyObject objectType, Type targetType) - { - if (targetType.IsGenericType) - { - targetType = targetType.GetGenericTypeDefinition(); - } - return decodableTypes.IndexOf(targetType) >= 0; - } - - public bool CanEncode(Type type) - { - return typeof(IList).IsAssignableFrom(type); - } - - public bool TryDecode(PyObject pyObj, out T value) - { - if (!PyIter.IsIterable(pyObj)) - { - value = default; - return false; - } - - using (var pyList = PyList.AsList(pyObj)) - { - if (typeof(T).IsGenericType) - { - value = pyList.ToList(); - } - else - { - value = (T)pyList.ToList(); - } - return true; - } - } - - public PyObject TryEncode(object value) - { - // This is a no-op to prevent Python.NET from encoding generic lists - // https://github.com/pythonnet/pythonnet/pull/963#issuecomment-642938541 - return PyObject.FromManagedObject(value); - } - } -} diff --git a/src/Libraries/DSCPython/Properties/AssemblyInfo.cs b/src/Libraries/DSCPython/Properties/AssemblyInfo.cs deleted file mode 100644 index 137353520d3..00000000000 --- a/src/Libraries/DSCPython/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("DSCPython")] -[assembly: AssemblyCulture("")] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("f1541c2d-80a9-4fe7-8d9e-75a8b9ff3479")] -[assembly: InternalsVisibleTo("PythonMigrationViewExtension")] -[assembly: InternalsVisibleTo("DynamoPythonTests")] diff --git a/src/Libraries/DSCPython/Properties/Resources.Designer.cs b/src/Libraries/DSCPython/Properties/Resources.Designer.cs deleted file mode 100644 index 947fdee8273..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.Designer.cs +++ /dev/null @@ -1,81 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace DSCPython.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DSCPython.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Output could not be converted to a .NET value. - /// - internal static string FailedToUnmarshalOutput { - get { - return ResourceManager.GetString("FailedToUnmarshalOutput", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Internal error, please report: Trace back information could not be extracted. - /// - internal static string InternalErrorTraceBackInfo { - get { - return ResourceManager.GetString("InternalErrorTraceBackInfo", resourceCulture); - } - } - } -} diff --git a/src/Libraries/DSCPython/Properties/Resources.cs-CZ.resx b/src/Libraries/DSCPython/Properties/Resources.cs-CZ.resx deleted file mode 100644 index ac9b92b8e9f..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.cs-CZ.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Výstup nebylo možné převést na hodnotu .NET. - - - Vnitřní chyba: Nahlaste tuto chybu: Informace o zpětném trasování nebylo možné extrahovat. - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/Properties/Resources.de-DE.resx b/src/Libraries/DSCPython/Properties/Resources.de-DE.resx deleted file mode 100644 index df1c932b5e5..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.de-DE.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Ausgabe konnte nicht in einen .NET-Wert konvertiert werden - - - Interner Fehler, bitte melden: Rückverfolgungsdaten konnten nicht extrahiert werden - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/Properties/Resources.en-GB.resx b/src/Libraries/DSCPython/Properties/Resources.en-GB.resx deleted file mode 100644 index 612371b7ef8..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.en-GB.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Output could not be converted to a .NET value - - - Internal error, please report: Trace back information could not be extracted - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/Properties/Resources.en-US.resx b/src/Libraries/DSCPython/Properties/Resources.en-US.resx deleted file mode 100644 index 612371b7ef8..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.en-US.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Output could not be converted to a .NET value - - - Internal error, please report: Trace back information could not be extracted - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/Properties/Resources.es-ES.resx b/src/Libraries/DSCPython/Properties/Resources.es-ES.resx deleted file mode 100644 index bfb1e843592..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.es-ES.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - La salida no se puede convertir a un valor de .NET. - - - Error interno, informe: no se ha podido extraer la información de seguimiento. - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/Properties/Resources.fr-FR.resx b/src/Libraries/DSCPython/Properties/Resources.fr-FR.resx deleted file mode 100644 index 2307ef05cef..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.fr-FR.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Impossible de convertir la sortie en une valeur .NET - - - Erreur interne. Veuillez signaler le message suivant: Impossible d'extraire les informations de retraçage - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/Properties/Resources.it-IT.resx b/src/Libraries/DSCPython/Properties/Resources.it-IT.resx deleted file mode 100644 index 4a321ac815a..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.it-IT.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Impossibile convertire l'output in un valore .NET - - - Errore interno, segnalare: impossibile estrarre le informazioni di traccia - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/Properties/Resources.ja-JP.resx b/src/Libraries/DSCPython/Properties/Resources.ja-JP.resx deleted file mode 100644 index 0f4f23b8e47..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.ja-JP.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 出力を .NET 値に変換できませんでした - - - 内部エラーです。次の内容を報告してください: トレース バック情報を抽出できませんでした - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/Properties/Resources.ko-KR.resx b/src/Libraries/DSCPython/Properties/Resources.ko-KR.resx deleted file mode 100644 index 947b2884d6b..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.ko-KR.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 출력을 .NET 값으로 변환할 수 없음 - - - '역추적 정보를 추출할 수 없습니다.'라는 내부 오류가 발생했습니다. 보고하십시오. - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/Properties/Resources.pl-PL.resx b/src/Libraries/DSCPython/Properties/Resources.pl-PL.resx deleted file mode 100644 index 63491fa96b4..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.pl-PL.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Nie można przekształcić wyjścia na wartość .NET - - - Błąd wewnętrzny, zgłoś: nie można wyodrębnić informacji śledzenia wstecznego - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/Properties/Resources.pt-BR.resx b/src/Libraries/DSCPython/Properties/Resources.pt-BR.resx deleted file mode 100644 index 2d4dbd48fef..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.pt-BR.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Não foi possível converter a saída em um valor .NET - - - Erro interno. Reporte: Não foi possível extrair as informações de reconstituição - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/Properties/Resources.resx b/src/Libraries/DSCPython/Properties/Resources.resx deleted file mode 100644 index 612371b7ef8..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Output could not be converted to a .NET value - - - Internal error, please report: Trace back information could not be extracted - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/Properties/Resources.ru-RU.resx b/src/Libraries/DSCPython/Properties/Resources.ru-RU.resx deleted file mode 100644 index 3158234b599..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.ru-RU.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Не удалось преобразовать выходные данные в значение .NET - - - Внутренняя ошибка. Сообщите о ней: не удалось извлечь информацию о трассировке - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/Properties/Resources.zh-CN.resx b/src/Libraries/DSCPython/Properties/Resources.zh-CN.resx deleted file mode 100644 index e96e895c985..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.zh-CN.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 输出无法转换为 .NET 值 - - - 内部错误,请报告: 无法提取跟踪回信息 - - \ No newline at end of file diff --git a/src/Libraries/DSCPython/Properties/Resources.zh-TW.resx b/src/Libraries/DSCPython/Properties/Resources.zh-TW.resx deleted file mode 100644 index b24b1cc0370..00000000000 --- a/src/Libraries/DSCPython/Properties/Resources.zh-TW.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 輸出無法轉換為 .NET 值 - - - 內部錯誤,請報告: 無法萃取追蹤回溯資訊 - - \ No newline at end of file diff --git a/src/Libraries/PythonNodeModels/Properties/Resources.Designer.cs b/src/Libraries/PythonNodeModels/Properties/Resources.Designer.cs index 967e1936916..418896ef84c 100644 --- a/src/Libraries/PythonNodeModels/Properties/Resources.Designer.cs +++ b/src/Libraries/PythonNodeModels/Properties/Resources.Designer.cs @@ -106,7 +106,7 @@ public static string PythonNodeContextMenuEngineSwitcher { } /// - /// Looks up a localized string similar to CPython3. + /// Looks up a localized string similar to PythonNet3. /// public static string PythonNodeContextMenuEngineVersionThree { get { @@ -176,6 +176,15 @@ public static string PythonScriptEditorConvertTabsToSpacesButtonTooltip { return ResourceManager.GetString("PythonScriptEditorConvertTabsToSpacesButtonTooltip", resourceCulture); } } + + /// + /// Looks up a localized string similar to Python Engine Automatically Updated to PythonNet3. + /// + public static string PythonScriptEditorEngineAutoUpdatedBarText { + get { + return ResourceManager.GetString("PythonScriptEditorEngineAutoUpdatedBarText", resourceCulture); + } + } /// /// Looks up a localized string similar to Select the Python version/engine to execute the script. @@ -185,6 +194,15 @@ public static string PythonScriptEditorEngineDropdownTooltip { return ResourceManager.GetString("PythonScriptEditorEngineDropdownTooltip", resourceCulture); } } + + /// + /// Looks up a localized string similar to Please update Python Engine to PythonNet3. + /// + public static string PythonScriptEditorEngineRequestToUpdatedBarText { + get { + return ResourceManager.GetString("PythonScriptEditorEngineRequestToUpdatedBarText", resourceCulture); + } + } /// /// Looks up a localized string similar to Load the Python Standard and DesignScript Libraries. @@ -204,6 +222,15 @@ public static string PythonScriptEditorInputComment { } } + /// + /// Looks up a localized string similar to Python engine has been automatically updated. No conversion necessary.. + /// + public static string PythonScriptEditorMigrationAssistantButtonDisabledTooltip { + get { + return ResourceManager.GetString("PythonScriptEditorMigrationAssistantButtonDisabledTooltip", resourceCulture); + } + } + /// /// Looks up a localized string similar to Convert script to Python 3.... /// @@ -331,7 +358,7 @@ public static string PythonScriptUnsavedChangesPromptTitle { } /// - /// Looks up a localized string similar to IronPython;CPython;. + /// Looks up a localized string similar to IronPython;PythonNet3;. /// public static string PythonSearchTags { get { diff --git a/src/Libraries/PythonNodeModels/Properties/Resources.en-US.resx b/src/Libraries/PythonNodeModels/Properties/Resources.en-US.resx index 1d27cda2185..6efed536ea9 100644 --- a/src/Libraries/PythonNodeModels/Properties/Resources.en-US.resx +++ b/src/Libraries/PythonNodeModels/Properties/Resources.en-US.resx @@ -133,7 +133,7 @@ Python Engine Version - CPython3 + PythonNet3 IronPython2 @@ -209,7 +209,7 @@ Convert script to Python 3... - IronPython;CPython; + IronPython;PythonNet3; It looks like you are still working on this. You may lose any unsaved changes if you leave now @@ -217,4 +217,16 @@ Are you sure you want to leave? - + + PythonNet3 + + + Python Engine Automatically Updated to PythonNet3 + + + Please update Python Engine to PythonNet3 + + + Python engine has been automatically updated. No conversion necessary. + + \ No newline at end of file diff --git a/src/Libraries/PythonNodeModels/Properties/Resources.resx b/src/Libraries/PythonNodeModels/Properties/Resources.resx index 6c3256d9426..b115e1fb6f3 100644 --- a/src/Libraries/PythonNodeModels/Properties/Resources.resx +++ b/src/Libraries/PythonNodeModels/Properties/Resources.resx @@ -133,7 +133,7 @@ Python Engine Version - CPython3 + PythonNet3 IronPython2 @@ -210,7 +210,7 @@ Convert indentation tabs to spaces... - IronPython;CPython; + IronPython;PythonNet3; It looks like you are still working on this. You may lose any unsaved changes if you leave now @@ -218,4 +218,16 @@ Are you sure you want to leave? - + + PythonNet3 + + + Python Engine Automatically Updated to PythonNet3 + + + Please update Python Engine to PythonNet3 + + + Python engine has been automatically updated. No conversion necessary. + + \ No newline at end of file diff --git a/src/Libraries/PythonNodeModels/PythonNode.cs b/src/Libraries/PythonNodeModels/PythonNode.cs index daa4d4e57b0..f6e2120d037 100644 --- a/src/Libraries/PythonNodeModels/PythonNode.cs +++ b/src/Libraries/PythonNodeModels/PythonNode.cs @@ -96,8 +96,8 @@ private void SetEngineByDefault() } else { - // Use CPython as default - engine = PythonEngineManager.CPython3EngineName; + // Use PythonNet3 as default + engine = PythonEngineManager.PythonNet3EngineName; } } @@ -184,6 +184,24 @@ protected override bool UpdateValueCore(UpdateValueParams updateValueParams) [IsDesignScriptCompatible] public sealed class PythonNode : PythonNodeBase { + private bool showAutoUpgradedBar; + /// + /// This property is true if the node was auto-upgraded from CPython3 to PythonNet3. + /// + [JsonIgnore] + public bool ShowAutoUpgradedBar + { + get => showAutoUpgradedBar; + internal set + { + if (showAutoUpgradedBar != value) + { + showAutoUpgradedBar = value; + RaisePropertyChanged(nameof(ShowAutoUpgradedBar)); + } + } + } + /// /// The NodeType property provides a name which maps to the /// server type for the node. This property should only be diff --git a/src/Libraries/PythonNodeModelsWpf/PythonNodeModelsWpf.csproj b/src/Libraries/PythonNodeModelsWpf/PythonNodeModelsWpf.csproj index a2805eb8c58..df27e01025c 100644 --- a/src/Libraries/PythonNodeModelsWpf/PythonNodeModelsWpf.csproj +++ b/src/Libraries/PythonNodeModelsWpf/PythonNodeModelsWpf.csproj @@ -24,6 +24,7 @@ + @@ -79,6 +80,7 @@ Designer + diff --git a/src/Libraries/PythonNodeModelsWpf/Resources/info.png b/src/Libraries/PythonNodeModelsWpf/Resources/info.png new file mode 100644 index 00000000000..8f5f523a15f Binary files /dev/null and b/src/Libraries/PythonNodeModelsWpf/Resources/info.png differ diff --git a/src/Libraries/PythonNodeModelsWpf/ScriptEditorWindow.xaml b/src/Libraries/PythonNodeModelsWpf/ScriptEditorWindow.xaml index b81f1e0831f..15684d58363 100644 --- a/src/Libraries/PythonNodeModelsWpf/ScriptEditorWindow.xaml +++ b/src/Libraries/PythonNodeModelsWpf/ScriptEditorWindow.xaml @@ -141,6 +141,7 @@ + @@ -302,10 +303,9 @@ Name="MigrationAssistantButton" Click="OnMigrationAssistantClicked" ToolTipService.ShowOnDisabled="True" - ToolTipService.IsEnabled="True" - IsEnabled="True"> + ToolTipService.IsEnabled="True"> - + + Grid.Row="3"> + Grid.Row="4"> + + + + + + + + + + + + + + +