PrEditor 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. preditor/__init__.py +315 -0
  2. preditor/__main__.py +13 -0
  3. preditor/about_module.py +165 -0
  4. preditor/cli.py +192 -0
  5. preditor/config.py +318 -0
  6. preditor/constants.py +13 -0
  7. preditor/contexts.py +210 -0
  8. preditor/cores/__init__.py +0 -0
  9. preditor/cores/core.py +20 -0
  10. preditor/dccs/.hab.json +10 -0
  11. preditor/dccs/maya/PrEditor_maya.mod +1 -0
  12. preditor/dccs/maya/README.md +22 -0
  13. preditor/dccs/maya/plug-ins/PrEditor_maya.py +141 -0
  14. preditor/dccs/studiomax/PackageContents.xml +32 -0
  15. preditor/dccs/studiomax/PrEditor-PrEditor_Show.mcr +8 -0
  16. preditor/dccs/studiomax/README.md +17 -0
  17. preditor/dccs/studiomax/preditor.ms +16 -0
  18. preditor/dccs/studiomax/preditor_menu.mnx +7 -0
  19. preditor/debug.py +149 -0
  20. preditor/delayable_engine/__init__.py +302 -0
  21. preditor/delayable_engine/delayables.py +85 -0
  22. preditor/enum.py +728 -0
  23. preditor/excepthooks.py +165 -0
  24. preditor/gui/__init__.py +56 -0
  25. preditor/gui/app.py +163 -0
  26. preditor/gui/codehighlighter.py +289 -0
  27. preditor/gui/completer.py +237 -0
  28. preditor/gui/console.py +605 -0
  29. preditor/gui/console_base.py +911 -0
  30. preditor/gui/dialog.py +181 -0
  31. preditor/gui/drag_tab_bar.py +625 -0
  32. preditor/gui/editor_chooser.py +57 -0
  33. preditor/gui/errordialog.py +69 -0
  34. preditor/gui/find_files.py +137 -0
  35. preditor/gui/fuzzy_search/__init__.py +0 -0
  36. preditor/gui/fuzzy_search/fuzzy_search.py +97 -0
  37. preditor/gui/group_tab_widget/__init__.py +0 -0
  38. preditor/gui/group_tab_widget/group_tab_widget.py +528 -0
  39. preditor/gui/group_tab_widget/grouped_tab_menu.py +35 -0
  40. preditor/gui/group_tab_widget/grouped_tab_models.py +107 -0
  41. preditor/gui/group_tab_widget/grouped_tab_widget.py +223 -0
  42. preditor/gui/group_tab_widget/one_tab_widget.py +96 -0
  43. preditor/gui/level_buttons.py +358 -0
  44. preditor/gui/logger_window_handler.py +77 -0
  45. preditor/gui/logger_window_plugin.py +35 -0
  46. preditor/gui/loggerwindow.py +2405 -0
  47. preditor/gui/newtabwidget.py +69 -0
  48. preditor/gui/output_console.py +11 -0
  49. preditor/gui/qtdesigner/__init__.py +21 -0
  50. preditor/gui/qtdesigner/_log_plugin.py +29 -0
  51. preditor/gui/qtdesigner/console_base_plugin.py +48 -0
  52. preditor/gui/qtdesigner/console_predit_plugin.py +48 -0
  53. preditor/gui/set_text_editor_path_dialog.py +61 -0
  54. preditor/gui/status_label.py +99 -0
  55. preditor/gui/suggest_path_quotes_dialog.py +50 -0
  56. preditor/gui/ui/editor_chooser.ui +93 -0
  57. preditor/gui/ui/errordialog.ui +74 -0
  58. preditor/gui/ui/find_files.ui +140 -0
  59. preditor/gui/ui/loggerwindow.ui +1909 -0
  60. preditor/gui/ui/set_text_editor_path_dialog.ui +189 -0
  61. preditor/gui/ui/suggest_path_quotes_dialog.ui +225 -0
  62. preditor/gui/window.py +161 -0
  63. preditor/gui/workbox_mixin.py +1139 -0
  64. preditor/gui/workbox_text_edit.py +136 -0
  65. preditor/gui/workboxwidget.py +315 -0
  66. preditor/logging_config.py +55 -0
  67. preditor/osystem.py +401 -0
  68. preditor/plugins.py +118 -0
  69. preditor/prefs.py +381 -0
  70. preditor/resource/environment_variables.html +26 -0
  71. preditor/resource/error_mail.html +85 -0
  72. preditor/resource/error_mail_inline.html +41 -0
  73. preditor/resource/img/README.md +17 -0
  74. preditor/resource/img/arrow_forward.png +0 -0
  75. preditor/resource/img/check-bold.png +0 -0
  76. preditor/resource/img/chevron-down.png +0 -0
  77. preditor/resource/img/chevron-up.png +0 -0
  78. preditor/resource/img/close-thick.png +0 -0
  79. preditor/resource/img/comment-edit.png +0 -0
  80. preditor/resource/img/content-copy.png +0 -0
  81. preditor/resource/img/content-cut.png +0 -0
  82. preditor/resource/img/content-duplicate.png +0 -0
  83. preditor/resource/img/content-paste.png +0 -0
  84. preditor/resource/img/content-save.png +0 -0
  85. preditor/resource/img/debug_disabled.png +0 -0
  86. preditor/resource/img/eye-check.png +0 -0
  87. preditor/resource/img/file-plus.png +0 -0
  88. preditor/resource/img/file-remove.png +0 -0
  89. preditor/resource/img/format-align-left.png +0 -0
  90. preditor/resource/img/format-letter-case-lower.png +0 -0
  91. preditor/resource/img/format-letter-case-upper.png +0 -0
  92. preditor/resource/img/format-letter-case.svg +1 -0
  93. preditor/resource/img/information.png +0 -0
  94. preditor/resource/img/logging_critical.png +0 -0
  95. preditor/resource/img/logging_custom.png +0 -0
  96. preditor/resource/img/logging_debug.png +0 -0
  97. preditor/resource/img/logging_error.png +0 -0
  98. preditor/resource/img/logging_info.png +0 -0
  99. preditor/resource/img/logging_not_set.png +0 -0
  100. preditor/resource/img/logging_warning.png +0 -0
  101. preditor/resource/img/marker.png +0 -0
  102. preditor/resource/img/play.png +0 -0
  103. preditor/resource/img/playlist-play.png +0 -0
  104. preditor/resource/img/plus-minus-variant.png +0 -0
  105. preditor/resource/img/preditor.ico +0 -0
  106. preditor/resource/img/preditor.png +0 -0
  107. preditor/resource/img/preditor.psd +0 -0
  108. preditor/resource/img/preditor.svg +44 -0
  109. preditor/resource/img/regex.svg +1 -0
  110. preditor/resource/img/restart.svg +1 -0
  111. preditor/resource/img/skip-forward-outline.png +0 -0
  112. preditor/resource/img/skip-next-outline.png +0 -0
  113. preditor/resource/img/skip-next.png +0 -0
  114. preditor/resource/img/skip-previous.png +0 -0
  115. preditor/resource/img/subdirectory-arrow-right.png +0 -0
  116. preditor/resource/img/text-search-variant.png +0 -0
  117. preditor/resource/img/warning-big.png +0 -0
  118. preditor/resource/lang/python.json +30 -0
  119. preditor/resource/pref_updates/pref_updates.json +17 -0
  120. preditor/resource/settings.ini +25 -0
  121. preditor/resource/stylesheet/Bright.css +76 -0
  122. preditor/resource/stylesheet/Dark.css +210 -0
  123. preditor/scintilla/__init__.py +40 -0
  124. preditor/scintilla/delayables/__init__.py +11 -0
  125. preditor/scintilla/delayables/smart_highlight.py +97 -0
  126. preditor/scintilla/delayables/spell_check.py +174 -0
  127. preditor/scintilla/documenteditor.py +1924 -0
  128. preditor/scintilla/finddialog.py +68 -0
  129. preditor/scintilla/lang/__init__.py +80 -0
  130. preditor/scintilla/lang/config/bash.ini +15 -0
  131. preditor/scintilla/lang/config/batch.ini +14 -0
  132. preditor/scintilla/lang/config/cpp.ini +19 -0
  133. preditor/scintilla/lang/config/css.ini +19 -0
  134. preditor/scintilla/lang/config/eyeonscript.ini +17 -0
  135. preditor/scintilla/lang/config/html.ini +21 -0
  136. preditor/scintilla/lang/config/javascript.ini +24 -0
  137. preditor/scintilla/lang/config/lua.ini +16 -0
  138. preditor/scintilla/lang/config/maxscript.ini +20 -0
  139. preditor/scintilla/lang/config/mel.ini +18 -0
  140. preditor/scintilla/lang/config/mu.ini +22 -0
  141. preditor/scintilla/lang/config/nsi.ini +19 -0
  142. preditor/scintilla/lang/config/perl.ini +19 -0
  143. preditor/scintilla/lang/config/puppet.ini +19 -0
  144. preditor/scintilla/lang/config/python.ini +28 -0
  145. preditor/scintilla/lang/config/ruby.ini +19 -0
  146. preditor/scintilla/lang/config/sql.ini +7 -0
  147. preditor/scintilla/lang/config/xml.ini +21 -0
  148. preditor/scintilla/lang/config/yaml.ini +18 -0
  149. preditor/scintilla/lang/language.py +240 -0
  150. preditor/scintilla/lexers/__init__.py +0 -0
  151. preditor/scintilla/lexers/cpplexer.py +22 -0
  152. preditor/scintilla/lexers/javascriptlexer.py +27 -0
  153. preditor/scintilla/lexers/maxscriptlexer.py +235 -0
  154. preditor/scintilla/lexers/mellexer.py +369 -0
  155. preditor/scintilla/lexers/mulexer.py +33 -0
  156. preditor/scintilla/lexers/pythonlexer.py +42 -0
  157. preditor/scintilla/ui/finddialog.ui +160 -0
  158. preditor/settings.py +71 -0
  159. preditor/stream/__init__.py +72 -0
  160. preditor/stream/console_handler.py +169 -0
  161. preditor/stream/director.py +144 -0
  162. preditor/stream/manager.py +97 -0
  163. preditor/streamhandler_helper.py +46 -0
  164. preditor/utils/__init__.py +191 -0
  165. preditor/utils/call_stack.py +86 -0
  166. preditor/utils/cute.py +106 -0
  167. preditor/utils/stylesheets.py +54 -0
  168. preditor/utils/text_search.py +338 -0
  169. preditor/version.py +34 -0
  170. preditor/weakref.py +363 -0
  171. preditor-2.1.0.dist-info/METADATA +308 -0
  172. preditor-2.1.0.dist-info/RECORD +179 -0
  173. preditor-2.1.0.dist-info/WHEEL +5 -0
  174. preditor-2.1.0.dist-info/entry_points.txt +19 -0
  175. preditor-2.1.0.dist-info/licenses/LICENSE +165 -0
  176. preditor-2.1.0.dist-info/top_level.txt +3 -0
  177. tests/encodings/test_ecoding.py +33 -0
  178. tests/find_files/test_find_files.py +74 -0
  179. tests/ide/test_delayable_engine.py +171 -0
@@ -0,0 +1,338 @@
1
+ from __future__ import absolute_import, print_function
2
+
3
+ import abc
4
+ import re
5
+ from collections import deque
6
+
7
+ from future.utils import with_metaclass
8
+
9
+
10
+ class TextSearch(with_metaclass(abc.ABCMeta, object)):
11
+ """Base class used to search and markup text for matches to a search term.
12
+
13
+ Parameters:
14
+ callback_matching (callable): Called when matching text should be written.
15
+ See `print_matching` to see what inputs it must accept.
16
+ callback_non_matching (callable): Called when plain text should be written.
17
+ See `print_non_matching` to see what inputs it must accept.
18
+ gap_format (str): A format string used to indicate when there is a gap in
19
+ the results shown. These variables are provided when formatting. `dot`
20
+ `dot` is a `.` for each digit required to show the current line number.
21
+ `padding` can be used to properly pad `dot`.
22
+ margin_format (str): A format string used to generate the line number
23
+ text at the start of a text line. These variables are provided when
24
+ formatting. `line_num` the current line number as an int. `padding`
25
+ can be used to properly pad `line_num`. `match_indicator` is a string
26
+ that is a `:` if the line contains a match, otherwise an empty space.
27
+ match_count (int): The number times matching text was found including
28
+ multiple finds on the same line. This value is not reset internally
29
+ and can be used to track all matches across multiple calls of `search_text`.
30
+ padding (int): Set by `search_text` to the number of digits required to
31
+ show all line numbers in the document. Used to ensure consistent number
32
+ padding for all line numbers printed in the margin and gaps.
33
+
34
+ Args:
35
+ find_text (str): The text this finder will search for.
36
+ case_sensitive (bool): When searching text should it ignore case.
37
+ context (int): The number of lines to show before and after a line with
38
+ a match.
39
+ """
40
+
41
+ def __init__(self, find_text, case_sensitive=False, context=3):
42
+ self._padding = 0
43
+ self.case_sensitive = case_sensitive
44
+ self.context = context
45
+ self.find_text = find_text
46
+ self.gap_format = " {dot: >{padding}} \n"
47
+ self.margin_format = " {line_num: >{padding}}{match_indicator} "
48
+ self.match_count = 0
49
+
50
+ self.callback_matching = self.print_matching
51
+ self.callback_non_matching = self.print_non_matching
52
+
53
+ def clear_cache(self):
54
+ """The finder can implement this to clear any cached data.
55
+
56
+ This is called when no matches have been found beyond the # of context lines
57
+ """
58
+
59
+ @abc.abstractmethod
60
+ def indicate_line(self, line):
61
+ """Yields chunks of line and if each chunk should be indicated.
62
+
63
+ The first yield should always be `(None, bool)`. The None value indicates
64
+ that the margin should be printed. This triggers printing of `self.margin`
65
+ passing the bool to the match_found argument.
66
+
67
+ Yields:
68
+ text (str or None): The text to be printed.
69
+ indicate (bool): Should text treated as a match for the search term.
70
+ """
71
+
72
+ def indicate_results(
73
+ self, line, line_num, path="undefined", workbox_name="undefined"
74
+ ):
75
+ """Writes a single line adding markup for any matches on the line."""
76
+ tool_tip = "Open {} at line number {}".format(path, line_num)
77
+ for text, indicate in self.indicate_line(line):
78
+ # Print the margin text after the finder tells us if the line matches
79
+ if text is None:
80
+ self.callback_non_matching(self.margin(line_num, indicate))
81
+ continue
82
+
83
+ # Otherwise print the next section of the line text
84
+ if indicate:
85
+ self.callback_matching(text, workbox_name, line_num, tool_tip)
86
+ else:
87
+ self.callback_non_matching(text)
88
+
89
+ def insert_lines(self, start, *lines, info):
90
+ """Inserts multiple lines adding links for any matching search terms.
91
+
92
+ Args:
93
+ start (int): The line number of the first line to insert.
94
+ *lines (str): Each line to insert. They will be prefixed with line
95
+ numbers starting with start.
96
+ info (dict): Kwargs passed to indicate_results.
97
+
98
+ Returns:
99
+ int: The line number of the last line that was inserted.
100
+ """
101
+ for i, line in enumerate(lines):
102
+ # Note: The `+ 1` is due to line numbers being 1 based not zero based
103
+ self.indicate_results(line, start + i + 1, **info)
104
+
105
+ return start + i
106
+
107
+ def margin(self, line_num, match_found):
108
+ """Returns the margin text rendered and ready to print.
109
+
110
+ Args:
111
+ line_num (int): The line number to show in the margin.
112
+ match_found (bool): Controls the indicator of if this line has any
113
+ matching text. If True then a `:` is inserted otherwise a space.
114
+ """
115
+ match_indicator = ":" if match_found else " "
116
+ return self.margin_format.format(
117
+ line_num=line_num, match_indicator=match_indicator, padding=self._padding
118
+ )
119
+
120
+ @abc.abstractmethod
121
+ def matches(self, line):
122
+ """Returns bool for if find_text is contained in this line."""
123
+
124
+ def print_matching(self, text, workbox_name, line_num, tool_tip):
125
+ """Simple callback for `callback_matching` that prints text.
126
+
127
+ The print does not insert an newline character.
128
+
129
+ Args:
130
+ text (str): The matching text to display. This will be inserted
131
+ into a markdown link as the link text.
132
+ workbox_name (str): From editor.__workbox_name__()
133
+ line_number (int): The line number the url should navigate to.
134
+ tool_tip (str): Added as a title to the link to show up as a tool tip.
135
+ """
136
+ href = ', {}, {}'.format(workbox_name, line_num)
137
+ print('[{}]({} "{}")'.format(text, href, tool_tip), end="")
138
+
139
+ def print_non_matching(self, text):
140
+ """Simple callback for `callback_non_matching` that prints text.
141
+
142
+ The print does not insert an newline character.
143
+ """
144
+ print(text, end="")
145
+
146
+ def search_text(self, text, path, workbox_name):
147
+ """Search each line of text for matching text and write the the matches
148
+ including context lines.
149
+
150
+ Args:
151
+ text (str): The text to search.
152
+ path (str): The workbox name this text represents. Should be the
153
+ Group_name and tab_name separated by a `/`.
154
+ workbox_name (str): From editor.__workbox_name__()
155
+ """
156
+ # NOTE: splitlines discards the "newline at end of file" so it doesn't
157
+ # show up in the final search results.
158
+ lines = text.splitlines(keepends=True)
159
+
160
+ # Calculate the padding count so we can ensure all line numbers and gaps
161
+ # are consistently spaced in the margins.
162
+ self._padding = len(str(len(lines)))
163
+
164
+ # Buffer to record up to context lines of text. This will be printed
165
+ # only if we find a match in the middle of the document.
166
+ # https://stackoverflow.com/a/52009859
167
+ pre_history = deque(maxlen=self.context)
168
+ remaining_context_lines = 0
169
+
170
+ # last_insert keeps track of the last time we inserted a line. This lets
171
+ # us keep track of if there is a gap in output and we need to add dots.
172
+ last_insert = 0
173
+ found = False
174
+
175
+ for i, line in enumerate(lines):
176
+ info = dict(path=path, workbox_name=workbox_name)
177
+ if self.matches(line):
178
+ len_pre_history = len(pre_history)
179
+ if not found:
180
+ # Print the path on the first find
181
+ self.callback_non_matching("# File: ")
182
+ tool_tip = "Open {}".format(path)
183
+ self.callback_matching(path, workbox_name, 0, tool_tip)
184
+ self.callback_non_matching("\n")
185
+ found = True
186
+ elif i - last_insert - 1 - len_pre_history > 0:
187
+ # If there is a in output larger than context, insert dots
188
+ # for the width of the line numbers to indicate the gap.
189
+ self.callback_non_matching(
190
+ self.gap_format.format(
191
+ dot='.' * len(str(i)), padding=self._padding
192
+ )
193
+ )
194
+ # Add the matching line the pre-context of the matching line.
195
+ last_insert = self.insert_lines(
196
+ i - len_pre_history, *pre_history, line, info=info
197
+ )
198
+ # Reset the pre-context history now that we have printed it.
199
+ pre_history.clear()
200
+ # Reset the post context line count so we will print the full
201
+ # context after this latest match if no other matches are found.
202
+ remaining_context_lines = self.context
203
+ else:
204
+ if remaining_context_lines > 0:
205
+ # Print any remaining context lines after we found a result
206
+ last_insert = self.insert_lines(i, line, info=info)
207
+ remaining_context_lines -= 1
208
+ else:
209
+ # If we don't need to print any post context lines record
210
+ # this line into pre-context history so we can print it if
211
+ # we find a match on the next line.
212
+ # When deque reaches maxlen lines, it automatically evicts oldest
213
+ pre_history.append(line)
214
+ # Clear any cached match information the finder may have stored.
215
+ self.clear_cache()
216
+
217
+ # Return if this file contained any matches
218
+ return found
219
+
220
+ def title(self):
221
+ return '\nFind in workboxs: "{}"{}\n\n'.format(self.find_text, self.title_flags)
222
+
223
+ @property
224
+ @abc.abstractmethod
225
+ def title_flags(self):
226
+ """Returns the text to show in the title for flags."""
227
+
228
+
229
+ class RegexTextSearch(TextSearch):
230
+ """TextSearch that processes the text using regex."""
231
+
232
+ def __init__(self, find_text, case_sensitive=False, context=3):
233
+ super(RegexTextSearch, self).__init__(
234
+ find_text, case_sensitive, context=context
235
+ )
236
+ self.pattern = re.compile(find_text, flags=0 if case_sensitive else re.I)
237
+ # Cache regex match objects between the `matches` call and `indicate_line`
238
+ # The key is the original line of text
239
+ self._matches = {}
240
+
241
+ def clear_cache(self):
242
+ # Reset regex cache for the next call to `matches`
243
+ self._matches = {}
244
+
245
+ def indicate_line(self, line):
246
+ # Check if this line is a match.
247
+ match = self._matches.get(line)
248
+ # Write the margin indicating if this line has any matches
249
+ yield None, bool(match)
250
+
251
+ start = 0
252
+ if match:
253
+ for m in match:
254
+ pre = line[start : m.start()]
255
+ if pre:
256
+ yield pre, False
257
+ yield line[m.start() : m.end()], True
258
+ start = m.end()
259
+ # Record the match
260
+ self.match_count += 1
261
+ post = line[start:]
262
+ if post:
263
+ yield post, False
264
+ else:
265
+ yield line, False
266
+
267
+ def matches(self, line):
268
+ self._matches[line] = list(self.pattern.finditer(line))
269
+ return bool(self._matches[line])
270
+
271
+ @property
272
+ def title_flags(self):
273
+ if self.case_sensitive:
274
+ return " (regex, case sensitive)"
275
+ return " (regex)"
276
+
277
+
278
+ class SimpleTextSearch(TextSearch):
279
+ """A simple text matching finder that optionally considers case."""
280
+
281
+ def __init__(self, find_text, case_sensitive=False, context=3):
282
+ super(SimpleTextSearch, self).__init__(
283
+ find_text, case_sensitive, context=context
284
+ )
285
+ # Assign the correct matching method based on the desired case setting
286
+ if case_sensitive:
287
+ self._matches = self._search_text_case_sensitive
288
+ else:
289
+ self._matches = self._search_text
290
+ find_text = self.find_text.lower()
291
+ # Preserve the original find_text value but cache the value needed internally
292
+ self._find_text = find_text
293
+
294
+ def _search_text(self, line):
295
+ """Check for pattern ignoring case."""
296
+ return self._find_text in line.lower()
297
+
298
+ def _search_text_case_sensitive(self, line):
299
+ """Check for pattern matching case."""
300
+ return self._find_text in line
301
+
302
+ def indicate_line(self, line):
303
+ # Handle case sensitivity setting, ensuring return of the correct case
304
+ original_line = line
305
+ if not self.case_sensitive:
306
+ line = line.lower()
307
+
308
+ find_len = len(self._find_text)
309
+ start = 0
310
+ end = line.find(self._find_text)
311
+ # Write the margin indicating if this line has any matches
312
+ yield None, end != -1
313
+
314
+ # Write the text of the line with indications
315
+ while end != -1:
316
+ # insert prefix text
317
+ yield original_line[start:end], False
318
+ # insert indicated text preserving case
319
+ yield original_line[end : end + find_len], True
320
+ # Record the match
321
+ self.match_count += 1
322
+
323
+ # Check for any more matches in this line
324
+ start = end + find_len
325
+ end = line.find(self._find_text, start)
326
+
327
+ # Include text at the end of the line
328
+ if end < find_len:
329
+ yield original_line[start:], False
330
+
331
+ def matches(self, line):
332
+ return self._matches(line)
333
+
334
+ @property
335
+ def title_flags(self):
336
+ if self.case_sensitive:
337
+ return " (case sensitive)"
338
+ return ""
preditor/version.py ADDED
@@ -0,0 +1,34 @@
1
+ # file generated by setuptools-scm
2
+ # don't change, don't track in version control
3
+
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
12
+
13
+ TYPE_CHECKING = False
14
+ if TYPE_CHECKING:
15
+ from typing import Tuple
16
+ from typing import Union
17
+
18
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
20
+ else:
21
+ VERSION_TUPLE = object
22
+ COMMIT_ID = object
23
+
24
+ version: str
25
+ __version__: str
26
+ __version_tuple__: VERSION_TUPLE
27
+ version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
30
+
31
+ __version__ = version = '2.1.0'
32
+ __version_tuple__ = version_tuple = (2, 1, 0)
33
+
34
+ __commit_id__ = commit_id = 'g5a664e468'