From 71aa22e36baa0802a04de5a018962bd1ecbdd5e1 Mon Sep 17 00:00:00 2001 From: Keith Alfaro Date: Fri, 8 Mar 2019 13:25:23 -0500 Subject: [PATCH] Provide a strategy for host integrator's to set the python template at startup (#9533) * provide a strategy for host integrators to set Python node template at startup programmatically * use 'is' as opposed to 'try/catch' * Fix several bugs around previously existing logging statements * add unit tests verifying valid and invalid API usage --- src/DynamoCore/Models/DynamoModel.cs | 65 ++++++++++++++++--- .../Properties/Resources.Designer.cs | 19 ++++-- .../Properties/Resources.en-US.resx | 12 ++++ src/DynamoCore/Properties/Resources.resx | 11 ++-- test/DynamoCoreTests/Settings.cs | 35 +++++++++- 5 files changed, 121 insertions(+), 21 deletions(-) diff --git a/src/DynamoCore/Models/DynamoModel.cs b/src/DynamoCore/Models/DynamoModel.cs index daac1961831..c29fda35470 100644 --- a/src/DynamoCore/Models/DynamoModel.cs +++ b/src/DynamoCore/Models/DynamoModel.cs @@ -521,6 +521,7 @@ public struct DefaultStartConfiguration : IStartConfiguration public IEnumerable Extensions { get; set; } public TaskProcessMode ProcessMode { get; set; } public bool IsHeadless { get; set; } + public string PythonTemplatePath { get; set; } } /// @@ -636,21 +637,50 @@ protected DynamoModel(IStartConfiguration config) var userDataFolder = pathManager.GetUserDataFolder(); // Get the default user data path AddPackagePath(userDataFolder); - // Check if the Python template file specified in the settings file exists & it's not empty - // If not, check the default filepath for the Python template (userDataFolder\PythonTemplate.py). - // If that doesn't exist either or is empty, Dynamo falls back to the hard-coded Python script template. - // We log the behaviour to make it easy for users to troubleshoot this. + // Load Python Template + // The loading pattern is conducted in the following order + // 1) Set from DynamoSettings.XML + // 2) Set from API via the configuration file + // 3) Set from PythonTemplate.py located in 'C:\Users\USERNAME\AppData\Roaming\Dynamo\Dynamo Core\2.X' + // 4) Set from OOTB hard-coded default template + + // If a custom python template path doesn't already exists in the DynamoSettings.xml if (string.IsNullOrEmpty(PreferenceSettings.PythonTemplateFilePath) || !File.Exists(PreferenceSettings.PythonTemplateFilePath)) { - if (string.IsNullOrEmpty(pathManager.PythonTemplateFilePath) || !File.Exists(pathManager.PythonTemplateFilePath)) - Logger.Log(Resources.PythonTemplateInvalid); + // To supply a custom python template host integrators should supply a 'DefaultStartConfiguration' config file + // or create a new struct that inherits from 'DefaultStartConfiguration' making sure to set the 'PythonTemplatePath' + // while passing the config to the 'DynamoModel' constructor. + if (config is DefaultStartConfiguration) + { + var configurationSettings = (DefaultStartConfiguration)config; + var templatePath = configurationSettings.PythonTemplatePath; + + // If a custom python template path was set in the config apply that template + if (!string.IsNullOrEmpty(templatePath) && File.Exists(templatePath)) + { + PreferenceSettings.PythonTemplateFilePath = templatePath; + Logger.Log(Resources.PythonTemplateDefinedByHost + " : " + PreferenceSettings.PythonTemplateFilePath); + } + + // Otherwise fallback to the default + else + { + SetDefaultPythonTemplate(); + } + } + else { - PreferenceSettings.PythonTemplateFilePath = pathManager.PythonTemplateFilePath; - Logger.Log(Resources.PythonTemplateDefaultFile + " : " + pathManager.PythonTemplateFilePath); + // Fallback to the default + SetDefaultPythonTemplate(); } } - else Logger.Log(Resources.PythonTemplateUserFile + " : " + pathManager.PythonTemplateFilePath); + + else + { + // A custom python template path already exists in the DynamoSettings.xml + Logger.Log(Resources.PythonTemplateUserFile + " : " + PreferenceSettings.PythonTemplateFilePath); + } pathManager.Preferences = PreferenceSettings; @@ -779,6 +809,23 @@ protected DynamoModel(IStartConfiguration config) DynamoReady(new ReadyParams(this)); } + private void SetDefaultPythonTemplate() + { + // First check if the default python template is overridden by a PythonTemplate.py file in AppData + // This file is always named accordingly and located in 'C:\Users\USERNAME\AppData\Roaming\Dynamo\Dynamo Core\2.X' + if (!string.IsNullOrEmpty(pathManager.PythonTemplateFilePath) && File.Exists(pathManager.PythonTemplateFilePath)) + { + PreferenceSettings.PythonTemplateFilePath = pathManager.PythonTemplateFilePath; + Logger.Log(Resources.PythonTemplateAppData + " : " + PreferenceSettings.PythonTemplateFilePath); + } + + // Otherwise the OOTB hard-coded template is applied + else + { + Logger.Log(Resources.PythonTemplateDefaultFile); + } + } + private void DynamoReadyExtensionHandler(ReadyParams readyParams, IEnumerable extensions) { foreach (var ext in extensions) diff --git a/src/DynamoCore/Properties/Resources.Designer.cs b/src/DynamoCore/Properties/Resources.Designer.cs index 53efd4f0a58..29a19fc343a 100644 --- a/src/DynamoCore/Properties/Resources.Designer.cs +++ b/src/DynamoCore/Properties/Resources.Designer.cs @@ -1151,7 +1151,16 @@ public static string ProceedButton { } /// - /// Looks up a localized string similar to Python template set to default file. + /// Looks up a localized string similar to Python template loaded from AppData. + /// + public static string PythonTemplateAppData { + get { + return ResourceManager.GetString("PythonTemplateAppData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Python template set to default.. /// public static string PythonTemplateDefaultFile { get { @@ -1160,16 +1169,16 @@ public static string PythonTemplateDefaultFile { } /// - /// Looks up a localized string similar to Python template : no valid template found.. + /// Looks up a localized string similar to Python template set by host integrator. /// - public static string PythonTemplateInvalid { + public static string PythonTemplateDefinedByHost { get { - return ResourceManager.GetString("PythonTemplateInvalid", resourceCulture); + return ResourceManager.GetString("PythonTemplateDefinedByHost", resourceCulture); } } /// - /// Looks up a localized string similar to Python template set to user file. + /// Looks up a localized string similar to Python template loaded from DynamoSettings.xml path. /// public static string PythonTemplateUserFile { get { diff --git a/src/DynamoCore/Properties/Resources.en-US.resx b/src/DynamoCore/Properties/Resources.en-US.resx index f761846505b..951352426c7 100644 --- a/src/DynamoCore/Properties/Resources.en-US.resx +++ b/src/DynamoCore/Properties/Resources.en-US.resx @@ -688,4 +688,16 @@ The input name should be a valid variable name, without spaces. An input type an Custom Node Contains Invalid Inputs and Cannot Be Saved. + + Python template loaded from AppData + + + Python template set to default. + + + Python template set by host integrator + + + Python template loaded from DynamoSettings.xml path + \ No newline at end of file diff --git a/src/DynamoCore/Properties/Resources.resx b/src/DynamoCore/Properties/Resources.resx index 96ecc6f937f..d5f9f63c10f 100644 --- a/src/DynamoCore/Properties/Resources.resx +++ b/src/DynamoCore/Properties/Resources.resx @@ -649,14 +649,14 @@ value : bool = false none - - Python template : no valid template found. + + Python template loaded from AppData - Python template set to default file + Python template set to default. - Python template set to user file + Python template loaded from DynamoSettings.xml path Home @@ -697,4 +697,7 @@ The input name should be a valid variable name, without spaces. An input type an Custom Node Contains Invalid Inputs and Cannot Be Saved. + + Python template set by host integrator + \ No newline at end of file diff --git a/test/DynamoCoreTests/Settings.cs b/test/DynamoCoreTests/Settings.cs index 5a5e775800a..d99885d88bf 100644 --- a/test/DynamoCoreTests/Settings.cs +++ b/test/DynamoCoreTests/Settings.cs @@ -1,9 +1,8 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; using Dynamo.Configuration; +using Dynamo.Models; using NUnit.Framework; namespace Dynamo.Tests @@ -55,6 +54,36 @@ public void LoadInvalidPythonTemplateFromSetting() Assert.AreEqual(settings.PythonTemplateFilePath, pyFile); } + [Test] + public void SetPythonTemplateFromConfigWithValidPath() + { + var templatePath = Path.Combine(SettingDirectory, "PythonTemplate-initial.py"); + + var config = new DynamoModel.DefaultStartConfiguration() + { + PythonTemplatePath = templatePath + }; + + var model = DynamoModel.Start(config); + + Assert.AreEqual(model.PreferenceSettings.PythonTemplateFilePath, templatePath); + } + + [Test] + public void SetPythonTemplateFromConfigWithInvalidPath() + { + var templatePath = Path.Combine(@"C:\Users\SomeDynamoUser\Desktop", "PythonTemplate-initial.py"); + + var config = new DynamoModel.DefaultStartConfiguration() + { + PythonTemplatePath = templatePath + }; + + var model = DynamoModel.Start(config); + + Assert.AreEqual(model.PreferenceSettings.PythonTemplateFilePath, string.Empty); + } + } }