From ebee018ba58d9e6fdd41041d565c66f1e68a4af8 Mon Sep 17 00:00:00 2001 From: pinzart90 <46732933+pinzart90@users.noreply.github.com> Date: Mon, 10 Feb 2025 13:22:59 -0500 Subject: [PATCH 1/4] Update ActionDebouncer.cs to support tests with no Sync context (#15804) Co-authored-by: Tiberiu Pinzariu --- .../Utilities/ActionDebouncer.cs | 23 +++++++++++++++++-- test/DynamoCoreWpfTests/DynamoTestUIBase.cs | 16 ++++++------- test/DynamoCoreWpfTests/RecordedTests.cs | 11 +++------ 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/DynamoCoreWpf/Utilities/ActionDebouncer.cs b/src/DynamoCoreWpf/Utilities/ActionDebouncer.cs index c1c89a3e2f6..969ea171df2 100644 --- a/src/DynamoCoreWpf/Utilities/ActionDebouncer.cs +++ b/src/DynamoCoreWpf/Utilities/ActionDebouncer.cs @@ -26,7 +26,7 @@ public void Cancel() /// /// Delays the "action" for a "timeout" number of milliseconds - /// The input Action will run on same syncronization context as the Debounce method call. + /// The input Action will run on same syncronization context as the Debounce method call (or the thread pool if a sync context does not exist, ex. in non UI tests). /// /// Number of milliseconds to wait /// The action to execute after the timeout runs out. @@ -36,6 +36,25 @@ public void Debounce(int timeout, Action action) Cancel(); cts = new CancellationTokenSource(); + // The TaskScheduler.FromCurrentSynchronizationContext() exists only if there is a valid SyncronizationContex. + // Calling this method from a non UI thread could have a null SyncronizationContex.Current, + // so in that case we use the default TaskScheduler which uses the thread pool. + TaskScheduler taskScheduler = null; + if (SynchronizationContext.Current != null) + {// This should always be the case in UI threads. + taskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); + } + else + { + // This might happen when running tests in non UI threads. + // But if we are in a UI thread, then log this as a potential error. + if (System.Windows.Application.Current?.Dispatcher?.Thread == Thread.CurrentThread) + {// UI thread. + logger?.LogError("The UI thread does not seem to have a SyncronizationContext."); + } + taskScheduler = TaskScheduler.Default; + } + Task.Delay(timeout, cts.Token).ContinueWith((t) => { try @@ -50,7 +69,7 @@ public void Debounce(int timeout, Action action) logger?.Log("Failed to run debounce action with the following error:"); logger?.Log(ex.ToString()); } - }, TaskScheduler.FromCurrentSynchronizationContext()); + }, taskScheduler); } public void Dispose() diff --git a/test/DynamoCoreWpfTests/DynamoTestUIBase.cs b/test/DynamoCoreWpfTests/DynamoTestUIBase.cs index 42d90b227d3..ce1c0cea825 100644 --- a/test/DynamoCoreWpfTests/DynamoTestUIBase.cs +++ b/test/DynamoCoreWpfTests/DynamoTestUIBase.cs @@ -59,7 +59,7 @@ private void PrettyPrint(object obj) Console.WriteLine("}"); } - internal void SetupStartupDiagnostics() + internal void StartupDiagnostics() { System.Console.WriteLine($"PID {Process.GetCurrentProcess().Id} Start test: {TestContext.CurrentContext.Test.Name}"); TestUtilities.WebView2Tag = TestContext.CurrentContext.Test.Name; @@ -69,7 +69,7 @@ internal void SetupStartupDiagnostics() Dispatcher.CurrentDispatcher.Hooks.OperationPosted += Hooks_OperationPosted; } - internal void SetupBeforeCleanupDiagnostics() + internal void BeforeCleanupDiagnostics() { Dispatcher.CurrentDispatcher.Hooks.OperationPosted -= Hooks_OperationPosted; if (!SkipDispatcherFlush) @@ -78,7 +78,7 @@ internal void SetupBeforeCleanupDiagnostics() } } - internal void SetupAfterCleanupDiagnostics() + internal void AfterCleanupDiagnostics() { TestUtilities.WebView2Tag = string.Empty; using (var currentProc = Process.GetCurrentProcess()) @@ -93,10 +93,10 @@ internal void SetupAfterCleanupDiagnostics() } } - internal void SetupCleanupDiagnostics() + internal void CleanupDiagnostics() { - SetupBeforeCleanupDiagnostics(); - SetupAfterCleanupDiagnostics(); + BeforeCleanupDiagnostics(); + AfterCleanupDiagnostics(); } } @@ -132,7 +132,7 @@ protected string ExecutingDirectory [SetUp] public virtual void Start() { - testDiagnostics.SetupStartupDiagnostics(); + testDiagnostics.StartupDiagnostics(); var assemblyPath = Assembly.GetExecutingAssembly().Location; preloader = new Preloader(Path.GetDirectoryName(assemblyPath)); preloader.Preload(); @@ -229,7 +229,7 @@ public void Exit() { Console.WriteLine(ex.StackTrace); } - testDiagnostics.SetupAfterCleanupDiagnostics(); + testDiagnostics.AfterCleanupDiagnostics(); } protected virtual void GetLibrariesToPreload(List libraries) diff --git a/test/DynamoCoreWpfTests/RecordedTests.cs b/test/DynamoCoreWpfTests/RecordedTests.cs index b328e5ead93..6da38d36665 100644 --- a/test/DynamoCoreWpfTests/RecordedTests.cs +++ b/test/DynamoCoreWpfTests/RecordedTests.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reflection; using System.Xml; using System.Threading; using CoreNodeModels.Input; @@ -24,10 +23,6 @@ using ProtoCore; using PythonNodeModels; using SystemTestServices; -using System.Windows.Threading; -using DynamoCoreWpfTests.Utility; -using System.Diagnostics; -using System.Threading.Tasks; namespace DynamoCoreWpfTests { @@ -54,7 +49,7 @@ public class RecordedUnitTestBase : DynamoViewModelUnitTest public override void Setup() { - testDiagnostics.SetupStartupDiagnostics(); + testDiagnostics.StartupDiagnostics(); base.Setup(); // Fixed seed randomizer for predictability. @@ -63,10 +58,10 @@ public override void Setup() public override void Cleanup() { - testDiagnostics.SetupBeforeCleanupDiagnostics(); + testDiagnostics.BeforeCleanupDiagnostics(); commandCallback = null; base.Cleanup(); - testDiagnostics.SetupAfterCleanupDiagnostics(); + testDiagnostics.AfterCleanupDiagnostics(); } #endregion From 512f789e9fd747b4598ace4534f7892e0f412316 Mon Sep 17 00:00:00 2001 From: dimven-adsk <123701487+dimven-adsk@users.noreply.github.com> Date: Tue, 11 Feb 2025 22:26:55 +0200 Subject: [PATCH 2/4] Improve graph opening times, reduce reflecion calls (#15761) Co-authored-by: pinzart90 Co-authored-by: Tiberiu Pinzariu --- src/DynamoCore/Graph/Nodes/NodeModel.cs | 11 +++++------ .../Graph/Nodes/ZeroTouch/DSFunctionBase.cs | 13 +++++++------ src/DynamoCore/PublicAPI.Unshipped.txt | 1 + src/DynamoPackages/PackageManagerExtension.cs | 5 +++-- src/Libraries/PythonNodeModels/PythonNode.cs | 13 +++++++------ 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/DynamoCore/Graph/Nodes/NodeModel.cs b/src/DynamoCore/Graph/Nodes/NodeModel.cs index 084a2dd8030..5791cf91648 100644 --- a/src/DynamoCore/Graph/Nodes/NodeModel.cs +++ b/src/DynamoCore/Graph/Nodes/NodeModel.cs @@ -1223,18 +1223,17 @@ protected NodeModel(IEnumerable inPorts, IEnumerable outPo RaisesModificationEvents = true; } + + internal protected AssemblyName NameOfAssemblyReferencedByNode = null; + /// /// The method returns the assembly name from which the node originated. /// /// Assembly Name internal virtual AssemblyName GetNameOfAssemblyReferencedByNode() { - AssemblyName assemblyName = null; - - var assembly = this.GetType().Assembly; - assemblyName = AssemblyName.GetAssemblyName(assembly.Location); - - return assemblyName; + NameOfAssemblyReferencedByNode ??= GetType().Assembly.GetName(); + return NameOfAssemblyReferencedByNode; } /// diff --git a/src/DynamoCore/Graph/Nodes/ZeroTouch/DSFunctionBase.cs b/src/DynamoCore/Graph/Nodes/ZeroTouch/DSFunctionBase.cs index 26ccfea9c91..e6dc1b6ca80 100644 --- a/src/DynamoCore/Graph/Nodes/ZeroTouch/DSFunctionBase.cs +++ b/src/DynamoCore/Graph/Nodes/ZeroTouch/DSFunctionBase.cs @@ -84,15 +84,16 @@ public override IdentifierNode GetAstIdentifierForOutputIndex(int outputIndex) /// Assembly Name internal override AssemblyName GetNameOfAssemblyReferencedByNode() { - AssemblyName assemblyName = null; - - var descriptor = this.Controller.Definition; - if (descriptor.IsPackageMember) + if (NameOfAssemblyReferencedByNode == null) { - assemblyName = AssemblyName.GetAssemblyName(descriptor.Assembly); + var descriptor = this.Controller.Definition; + if (descriptor.IsPackageMember) + { + NameOfAssemblyReferencedByNode = AssemblyName.GetAssemblyName(descriptor.Assembly); + } } - return assemblyName; + return NameOfAssemblyReferencedByNode; } /// diff --git a/src/DynamoCore/PublicAPI.Unshipped.txt b/src/DynamoCore/PublicAPI.Unshipped.txt index f87678d8cef..7d9729b6412 100644 --- a/src/DynamoCore/PublicAPI.Unshipped.txt +++ b/src/DynamoCore/PublicAPI.Unshipped.txt @@ -1004,6 +1004,7 @@ Dynamo.Graph.Nodes.NodeModel.MarkNodeAsModified(bool forceExecute = false) -> vo Dynamo.Graph.Nodes.NodeModel.Modified -> System.Action Dynamo.Graph.Nodes.NodeModel.Name.get -> string Dynamo.Graph.Nodes.NodeModel.Name.set -> void +Dynamo.Graph.Nodes.NodeModel.NameOfAssemblyReferencedByNode -> System.Reflection.AssemblyName Dynamo.Graph.Nodes.NodeModel.NeedsForceExecution.get -> bool Dynamo.Graph.Nodes.NodeModel.NodeExecutionBegin -> System.Action Dynamo.Graph.Nodes.NodeModel.NodeExecutionEnd -> System.Action diff --git a/src/DynamoPackages/PackageManagerExtension.cs b/src/DynamoPackages/PackageManagerExtension.cs index 3c3bf454b28..257eb61a63e 100644 --- a/src/DynamoPackages/PackageManagerExtension.cs +++ b/src/DynamoPackages/PackageManagerExtension.cs @@ -277,10 +277,11 @@ private void OnCurrentWorkspaceChanged(IWorkspaceModel ws) private PackageInfo GetNodePackageFromAssemblyName(AssemblyName assemblyName) { - if (NodePackageDictionary != null && NodePackageDictionary.ContainsKey(assemblyName.FullName)) + if (NodePackageDictionary?.TryGetValue(assemblyName.FullName, out var packages) == true) { - return NodePackageDictionary[assemblyName.FullName].Last(); + return packages.Last(); } + return null; } diff --git a/src/Libraries/PythonNodeModels/PythonNode.cs b/src/Libraries/PythonNodeModels/PythonNode.cs index d7427ac9d26..fbfd61e9197 100644 --- a/src/Libraries/PythonNodeModels/PythonNode.cs +++ b/src/Libraries/PythonNodeModels/PythonNode.cs @@ -70,15 +70,16 @@ public string EngineName /// Assembly Name internal override AssemblyName GetNameOfAssemblyReferencedByNode() { - AssemblyName assemblyName = null; - - var pyEng = PythonEngineManager.Instance.AvailableEngines.Where(x => x.Name.Equals(this.EngineName)).FirstOrDefault(); - if (pyEng != null) + if (NameOfAssemblyReferencedByNode == null) { - assemblyName = AssemblyName.GetAssemblyName(pyEng.GetType().Assembly.Location); + var pyEng = PythonEngineManager.Instance.AvailableEngines.Where(x => x.Name.Equals(this.EngineName)).FirstOrDefault(); + if (pyEng != null) + { + NameOfAssemblyReferencedByNode = pyEng.GetType().Assembly.GetName(); + } } - return assemblyName; + return NameOfAssemblyReferencedByNode; } /// From 171e233845059548096a0784ef2d8c3831304d85 Mon Sep 17 00:00:00 2001 From: reddyashish <43763136+reddyashish@users.noreply.github.com> Date: Tue, 11 Feb 2025 12:35:10 -0800 Subject: [PATCH 3/4] [DYN-7366] Fix CER crash on ConnectorViewModel (#15816) --- .../ViewModels/Core/ConnectorViewModel.cs | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/DynamoCoreWpf/ViewModels/Core/ConnectorViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/ConnectorViewModel.cs index f3da4ee62d2..cf6e719d70c 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/ConnectorViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/ConnectorViewModel.cs @@ -1222,16 +1222,20 @@ public override void Dispose() { NodeEnd.PropertyChanged -= nodeEndViewModel_PropertyChanged; } - ConnectorPinViewCollection.CollectionChanged -= HandleCollectionChanged; - workspaceViewModel.PropertyChanged -= WorkspaceViewModel_PropertyChanged; - - foreach (var pin in ConnectorPinViewCollection.ToList()) + if (ConnectorPinViewCollection != null) { - pin.RequestRedraw -= HandlerRedrawRequest; - pin.RequestSelect -= HandleRequestSelected; + ConnectorPinViewCollection.CollectionChanged -= HandleCollectionChanged; + + foreach (var pin in ConnectorPinViewCollection.ToList()) + { + pin.RequestRedraw -= HandlerRedrawRequest; + pin.RequestSelect -= HandleRequestSelected; + } } + workspaceViewModel.PropertyChanged -= WorkspaceViewModel_PropertyChanged; + this.PropertyChanged -= ConnectorViewModelPropertyChanged; DiscardAllConnectorPinModels(); @@ -1451,17 +1455,27 @@ internal List CollectPinLocations() /// public void Redraw() { - if (this.ConnectorModel?.End != null && ConnectorPinViewCollection?.Count > 0) + try { - RedrawBezierManyPoints(); + if (this.ConnectorModel != null && ConnectorPinViewCollection != null) + { + if (this.ConnectorModel?.End != null && ConnectorPinViewCollection?.Count > 0) + { + RedrawBezierManyPoints(); + } + else if (this.ConnectorModel?.End != null) + { + this.Redraw(this.ConnectorModel.End.Center); + } + } + + this.SetCollapsedByNodeViewModel(); + RaisePropertyChanged(nameof(ZIndex)); } - else if (this.ConnectorModel?.End != null) + catch (Exception ex) { - this.Redraw(this.ConnectorModel.End.Center); + workspaceViewModel.DynamoViewModel.Model.Logger.Log("Error when redrawing the connector: " + ex.StackTrace); } - - this.SetCollapsedByNodeViewModel(); - RaisePropertyChanged(nameof(ZIndex)); } /// From b00145de5f063c089fec3dd3bbb34fe67a9d523a Mon Sep 17 00:00:00 2001 From: reddyashish <43763136+reddyashish@users.noreply.github.com> Date: Thu, 13 Feb 2025 13:27:01 -0800 Subject: [PATCH 4/4] [DYN-8019] Fix package - install to folder function. (#15826) --- .../PackageManager/PackageManagerSearchViewModel.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerSearchViewModel.cs b/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerSearchViewModel.cs index 60eacd1af20..1ea7c92f3be 100644 --- a/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerSearchViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerSearchViewModel.cs @@ -724,7 +724,6 @@ private void PopulateMyPackages() var p = GetSearchElementViewModel(pkg, true); p.RequestDownload += this.PackageOnExecuted; - p.RequestShowFileDialog += this.OnRequestShowFileDialog; p.IsOnwer = true; myPackages.Add(p); @@ -1239,6 +1238,8 @@ internal void RefreshInfectedPackages() internal void AddToSearchResults(PackageManagerSearchElementViewModel element) { element.RequestDownload += this.PackageOnExecuted; + element.RequestShowFileDialog += this.OnRequestShowFileDialog; + this.SearchResults.Add(element); } @@ -1479,9 +1480,6 @@ internal IEnumerable GetAllPackages() list.Reverse(); } - foreach (var x in list) - x.RequestShowFileDialog += OnRequestShowFileDialog; - return list; }