Lean  $LEAN_TAG$
Messages.Python.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System.IO;
17 using System.Runtime.CompilerServices;
18 using System.Collections.Generic;
19 
20 using Python.Runtime;
21 using System;
22 using System.Linq;
23 
24 namespace QuantConnect
25 {
26  /// <summary>
27  /// Provides user-facing message construction methods and static messages for the <see cref="Python"/> namespace
28  /// </summary>
29  public static partial class Messages
30  {
31  /// <summary>
32  /// Provides user-facing common messages for the <see cref="Python"/> namespace classes
33  /// </summary>
34  public static class PythonCommon
35  {
36  /// <summary>
37  /// Returns a string message saying the given attribute must be implemented on the given Python type
38  /// </summary>
39  [MethodImpl(MethodImplOptions.AggressiveInlining)]
40  public static string AttributeNotImplemented(string attribute, PyType pythonType)
41  {
42  return $"{attribute} must be implemented. Please implement this missing method on {pythonType}";
43  }
44  }
45 
46  /// <summary>
47  /// Provides user-facing common messages for the <see cref="Python.MarginCallModelPythonWrapper"/> namespace classes
48  /// </summary>
49  public static class MarginCallModelPythonWrapper
50  {
51  /// <summary>
52  /// String message saying: Must return a tuple, where the first item is a list and the second a boolean
53  /// </summary>
54  public static string GetMarginCallOrdersMustReturnTuple = "Must return a tuple, where the first item is a list and the second a boolean";
55  }
56 
57  /// <summary>
58  /// Provides user-facing common messages for the <see cref="Python.PandasConverter"/> namespace classes
59  /// </summary>
60  public static class PandasConverter
61  {
62  /// <summary>
63  /// String message saying: Pandas module was not imported
64  /// </summary>
65  public static string PandasModuleNotImported = "pandas module was not imported.";
66 
67  /// <summary>
68  /// Returns a string message saying ConvertToDictionary() method cannot be used to convert the given source
69  /// type into the given target type. It also contains the reason why this method cannot be used
70  /// </summary>
71  [MethodImpl(MethodImplOptions.AggressiveInlining)]
72  public static string ConvertToDictionaryFailed(string sourceType, string targetType, string reason)
73  {
74  return $"ConvertToDictionary cannot be used to convert a {sourceType} into {targetType}. Reason: {reason}";
75  }
76  }
77 
78  /// <summary>
79  /// Provides user-facing common messages for the <see cref="Python.PandasData"/> namespace classes
80  /// </summary>
81  public static class PandasData
82  {
83  /// <summary>
84  /// Returns a string message saying the given key was duplicated in the given
85  /// type class
86  /// </summary>
87  [MethodImpl(MethodImplOptions.AggressiveInlining)]
88  public static string DuplicateKey(string duplicateKey, string type)
89  {
90  return $"More than one '{duplicateKey}' member was found in '{type}' class.";
91  }
92 
93  /// <summary>
94  /// Returns a string message saying the given key does not exist in series dictionary
95  /// </summary>
96  [MethodImpl(MethodImplOptions.AggressiveInlining)]
97  public static string KeyNotFoundInSeries(string key)
98  {
99  return $"{key} key does not exist in series dictionary.";
100  }
101  }
102 
103  /// <summary>
104  /// Provides user-facing common messages for the <see cref="Python.PythonInitializer"/> namespace classes
105  /// </summary>
106  public static class PythonInitializer
107  {
108  /// <summary>
109  /// String message saying: start
110  /// </summary>
111  public static string Start = "start";
112 
113  /// <summary>
114  /// String message saying: ended
115  /// </summary>
116  public static string Ended = "ended";
117 
118  /// <summary>
119  /// Returns a string message saying it was impossible to find algorithm location path
120  /// </summary>
121  [MethodImpl(MethodImplOptions.AggressiveInlining)]
122  public static string UnableToLocateAlgorithm(string algorithmLocation)
123  {
124  return $"Unable to find algorithm location path: {algorithmLocation}.";
125  }
126 
127  /// <summary>
128  /// Returns a string message saying the given path to virtual environment does not exist
129  /// </summary>
130  [MethodImpl(MethodImplOptions.AggressiveInlining)]
131  public static string VirutalEnvironmentNotFound(string virtualEnvPath)
132  {
133  return $"Path {virtualEnvPath} to virtual environment does not exist.";
134  }
135 
136  /// <summary>
137  /// Returns a string message saying it was impossible to find system package configuration
138  /// </summary>
139  [MethodImpl(MethodImplOptions.AggressiveInlining)]
140  public static string FailedToFindSystemPackagesConfiguration(string virtualEnvPath, FileInfo configFile)
141  {
142  return $@"virtual env '{virtualEnvPath}'. Failed to find system packages configuration. ConfigFile.Exits: {
143  configFile.Exists}. Will default to true.";
144  }
145 
146  /// <summary>
147  /// Returns a string message saying the Python Initializer will use the system packages found
148  /// in the virtual environment path
149  /// </summary>
150  [MethodImpl(MethodImplOptions.AggressiveInlining)]
151  public static string SystemPackagesConfigurationFound(string virtualEnvPath, bool includeSystemPackages)
152  {
153  return $"virtual env '{virtualEnvPath}'. Will use system packages: {includeSystemPackages}";
154  }
155 
156  /// <summary>
157  /// Returns a string message saying it was impossible to find the given python path
158  /// </summary>
159  [MethodImpl(MethodImplOptions.AggressiveInlining)]
160  public static string PythonPathNotFound(string pythonPath)
161  {
162  return $"Unable to find python path: {pythonPath}. Skipping.";
163  }
164  }
165 
166  /// <summary>
167  /// Provides user-facing common messages for the <see cref="Python.PythonWrapper"/> namespace classes
168  /// </summary>
169  public static class PythonWrapper
170  {
171  /// <summary>
172  /// String message saying: expected and interface type parameter
173  /// </summary>
174  public static string ExpectedInterfaceTypeParameter = "expected an interface type parameter.";
175 
176  /// <summary>
177  /// Returns a string message saying the given interface must be fully implemented. It also advises the user
178  /// on the missing methods in its interface
179  /// </summary>
180  [MethodImpl(MethodImplOptions.AggressiveInlining)]
181  public static string InterfaceNotFullyImplemented(string interfaceName, string pythonTypeName, IEnumerable<string> missingMembers)
182  {
183  return $@"{interfaceName} must be fully implemented. Please implement these missing methods on {
184  pythonTypeName}: {string.Join(", ", missingMembers)}";
185  }
186  }
187 
188  /// <summary>
189  /// Provides user-facing common messages for the <see cref="Python.BasePythonWrapper{TInterface}"/> class
190  /// </summary>
191  public static class BasePythonWrapper
192  {
193  [MethodImpl(MethodImplOptions.AggressiveInlining)]
194  public static string InvalidDictionaryValueType(string pythonMethodName, Type expectedType, PyType actualPyType)
195  {
196  return InvalidDictionaryItemType(pythonMethodName, expectedType, actualPyType, isKey: false);
197  }
198 
199  [MethodImpl(MethodImplOptions.AggressiveInlining)]
200  public static string InvalidDictionaryKeyType(string pythonMethodName, Type expectedType, PyType actualPyType)
201  {
202  return InvalidDictionaryItemType(pythonMethodName, expectedType, actualPyType, isKey: true);
203  }
204 
205  [MethodImpl(MethodImplOptions.AggressiveInlining)]
206  public static string InvalidReturnTypeForMethodWithOutParameters(string pythonMethodName, PyType pyValueType)
207  {
208  return $"Invalid return type from method '{pythonMethodName.ToSnakeCase()}'. Expected a tuple type but was " +
209  $"'{GetPythonTypeName(pyValueType)}'. The tuple must contain the return value as the first item, " +
210  $"with the remaining ones being the out parameters.";
211  }
212 
213  [MethodImpl(MethodImplOptions.AggressiveInlining)]
214  public static string InvalidReturnTypeTupleSizeForMethodWithOutParameters(string pythonMethodName, long expectedSize, long actualSize)
215  {
216  return $"Invalid return type from method '{pythonMethodName.ToSnakeCase()}'. Expected a tuple with at least " +
217  $"'{expectedSize}' items but only '{actualSize}' were returned. " +
218  $"The tuple must contain the return value as the first item, with the remaining ones being the out parameters.";
219  }
220 
221  [MethodImpl(MethodImplOptions.AggressiveInlining)]
222  public static string InvalidOutParameterType(string pythonMethodName, int index, Type expectedType, PyType actualPyType)
223  {
224  return $"Invalid out parameter type in method '{pythonMethodName.ToSnakeCase()}'. Out parameter in position {index} " +
225  $"expected type is '{expectedType.Name}' but was '{GetPythonTypeName(actualPyType)}'.";
226  }
227 
228  [MethodImpl(MethodImplOptions.AggressiveInlining)]
229  public static string InvalidReturnType(string pythonName, Type expectedType, PyType actualPyType, bool isMethod = true)
230  {
231  var message = isMethod
232  ? $"Invalid return type from method '{pythonName.ToSnakeCase()}'. "
233  : $"Invalid type for property '{pythonName.ToSnakeCase()}'. ";
234  message += $"Expected a type convertible to '{expectedType.Name}' but was '{GetPythonTypeName(actualPyType)}'";
235  return message;
236  }
237 
238  [MethodImpl(MethodImplOptions.AggressiveInlining)]
239  public static string InvalidIterable(string pythonMethodName, Type expectedType, PyType actualPyType)
240  {
241  return $"Invalid return type from method '{pythonMethodName.ToSnakeCase()}'. " +
242  $"Expected an iterable type of '{expectedType.Name}' items but was '{GetPythonTypeName(actualPyType)}'";
243  }
244 
245  [MethodImpl(MethodImplOptions.AggressiveInlining)]
246  public static string InvalidMethodIterableItemType(string pythonMethodName, Type expectedType, PyType actualPyType)
247  {
248  return $"Invalid return type from method '{pythonMethodName.ToSnakeCase()}'. Expected all the items in the iterator to be of type " +
249  $"'{expectedType.Name}' but found one of type ' {GetPythonTypeName(actualPyType)}'";
250  }
251 
252  [MethodImpl(MethodImplOptions.AggressiveInlining)]
253  private static string InvalidDictionaryItemType(string pythonMethodName, Type expectedType, PyType actualPyType, bool isKey = true)
254  {
255  return $"Invalid value type from method or property '{pythonMethodName.ToSnakeCase()}'. " +
256  $"Expected all the {(isKey ? "keys" : "values")} in the dictionary to be of type '{expectedType.Name}' " +
257  $"but found one of type '{GetPythonTypeName(actualPyType)}'";
258  }
259 
260  [MethodImpl(MethodImplOptions.AggressiveInlining)]
261  private static string GetPythonTypeName(PyType pyType)
262  {
263  return pyType.Name.Split('.').Last();
264  }
265  }
266  }
267 }