InquirerPrompt 0.3.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.
@@ -0,0 +1,621 @@
1
+ """Module contains the class to create a number prompt."""
2
+
3
+ import re
4
+ from decimal import Decimal
5
+ from typing import TYPE_CHECKING, Any, Callable, Optional, Tuple, Union, cast
6
+
7
+ from prompt_toolkit.application.application import Application
8
+ from prompt_toolkit.buffer import Buffer
9
+ from prompt_toolkit.filters.base import Condition
10
+ from prompt_toolkit.filters.cli import IsDone
11
+ from prompt_toolkit.keys import Keys
12
+ from prompt_toolkit.layout.containers import (
13
+ ConditionalContainer,
14
+ HorizontalAlign,
15
+ HSplit,
16
+ VSplit,
17
+ Window,
18
+ )
19
+ from prompt_toolkit.layout.controls import (
20
+ BufferControl,
21
+ DummyControl,
22
+ FormattedTextControl,
23
+ )
24
+ from prompt_toolkit.layout.dimension import Dimension, LayoutDimension
25
+ from prompt_toolkit.layout.layout import Layout
26
+ from prompt_toolkit.lexers.base import SimpleLexer
27
+ from prompt_toolkit.validation import ValidationError
28
+
29
+ from InquirerPy.base.complex import BaseComplexPrompt, FakeDocument
30
+ from InquirerPy.containers.instruction import InstructionWindow
31
+ from InquirerPy.containers.validation import ValidationWindow
32
+ from InquirerPy.enum import INQUIRERPY_QMARK_SEQUENCE
33
+ from InquirerPy.exceptions import InvalidArgument
34
+ from InquirerPy.utils import (
35
+ InquirerPyDefault,
36
+ InquirerPyKeybindings,
37
+ InquirerPyMessage,
38
+ InquirerPySessionResult,
39
+ InquirerPyStyle,
40
+ InquirerPyValidate,
41
+ )
42
+
43
+ if TYPE_CHECKING:
44
+ from prompt_toolkit.key_binding.key_processor import KeyPressEvent
45
+
46
+ __all__ = ["NumberPrompt"]
47
+
48
+
49
+ class NumberPrompt(BaseComplexPrompt):
50
+ """Create a input prompts that only takes number as input.
51
+
52
+ A wrapper class around :class:`~prompt_toolkit.application.Application`.
53
+
54
+ Args:
55
+ message: The question to ask the user.
56
+ Refer to :ref:`pages/dynamic:message` documentation for more details.
57
+ style: An :class:`InquirerPyStyle` instance.
58
+ Refer to :ref:`Style <pages/style:Alternate Syntax>` documentation for more details.
59
+ vi_mode: Use vim keybinding for the prompt.
60
+ Refer to :ref:`pages/kb:Keybindings` documentation for more details.
61
+ default: Set the default value of the prompt.
62
+ You can enter either the floating value or integer value as the default.
63
+ Refer to :ref:`pages/dynamic:default` documentation for more details.
64
+ float_allowed: Allow decimal input. This will change the prompt to have 2 input buffer, one for the
65
+ whole value and one for the integral value.
66
+ min_allowed: Set the minimum value of the prompt. When the input value goes below this value, it
67
+ will automatically reset to this value.
68
+ max_allowed: Set the maximum value of the prompt. When the inptu value goes above this value, it
69
+ will automatically reset to this value.
70
+ qmark: Question mark symbol. Custom symbol that will be displayed infront of the question before its answered.
71
+ amark: Answer mark symbol. Custom symbol that will be displayed infront of the question after its answered.
72
+ decimal_symbol: Decimal point symbol. Custom symbol to display as the decimal point.
73
+ replace_mode: Start each input buffer in replace mode if default value is 0.
74
+ When typing, it will replace the 0 with the new value. The replace mode will be disabled once the value
75
+ is changed.
76
+ instruction: Short instruction to display next to the question.
77
+ long_instruction: Long instructions to display at the bottom of the prompt.
78
+ validate: Add validation to user input.
79
+ Refer to :ref:`pages/validator:Validator` documentation for more details.
80
+ invalid_message: Error message to display when user input is invalid.
81
+ Refer to :ref:`pages/validator:Validator` documentation for more details.
82
+ invalid_message: Error message to display when user input is invalid.
83
+ Refer to :ref:`pages/validator:Validator` documentation for more details.
84
+ transformer: A function which performs additional transformation on the value that gets printed to the terminal.
85
+ Different than `filter` parameter, this is only visual effect and won’t affect the actual value returned by :meth:`~InquirerPy.base.simple.BaseSimplePrompt.execute`.
86
+ Refer to :ref:`pages/dynamic:transformer` documentation for more details.
87
+ filter: A function which performs additional transformation on the result.
88
+ This affects the actual value returned by :meth:`~InquirerPy.base.simple.BaseSimplePrompt.execute`.
89
+ Refer to :ref:`pages/dynamic:filter` documentation for more details.
90
+ keybindings: Customise the builtin keybindings.
91
+ Refer to :ref:`pages/kb:Keybindings` for more details.
92
+ wrap_lines: Soft wrap question lines when question exceeds the terminal width.
93
+ raise_keyboard_interrupt: Raise the :class:`KeyboardInterrupt` exception when `ctrl-c` is pressed. If false, the result
94
+ will be `None` and the question is skiped.
95
+ mandatory: Indicate if the prompt is mandatory. If True, then the question cannot be skipped.
96
+ mandatory_message: Error message to show when user attempts to skip mandatory prompt.
97
+ session_result: Used internally for :ref:`index:Classic Syntax (PyInquirer)`.
98
+
99
+ Examples:
100
+ >>> from InquirerPy import inquirer
101
+ >>> result = inquirer.number(message="Enter number:").execute()
102
+ >>> print(result)
103
+ 0
104
+ """
105
+
106
+ def __init__(
107
+ self,
108
+ message: InquirerPyMessage,
109
+ style: Optional[InquirerPyStyle] = None,
110
+ vi_mode: bool = False,
111
+ default: InquirerPyDefault = 0,
112
+ float_allowed: bool = False,
113
+ max_allowed: Optional[Union[int, float]] = None,
114
+ min_allowed: Optional[Union[int, float]] = None,
115
+ decimal_symbol: str = ". ",
116
+ replace_mode: bool = False,
117
+ qmark: str = INQUIRERPY_QMARK_SEQUENCE,
118
+ amark: str = "?",
119
+ instruction: str = "",
120
+ long_instruction: str = "",
121
+ validate: Optional[InquirerPyValidate] = None,
122
+ invalid_message: str = "Invalid input",
123
+ transformer: Optional[Callable[[str], Any]] = None,
124
+ filter: Optional[Callable[[str], Any]] = None,
125
+ keybindings: Optional[InquirerPyKeybindings] = None,
126
+ wrap_lines: bool = True,
127
+ raise_keyboard_interrupt: bool = True,
128
+ mandatory: bool = True,
129
+ mandatory_message: str = "Mandatory prompt",
130
+ session_result: Optional[InquirerPySessionResult] = None,
131
+ ) -> None:
132
+ super().__init__(
133
+ message=message,
134
+ style=style,
135
+ vi_mode=vi_mode,
136
+ qmark=qmark,
137
+ amark=amark,
138
+ transformer=transformer,
139
+ filter=filter,
140
+ invalid_message=invalid_message,
141
+ validate=validate,
142
+ instruction=instruction,
143
+ long_instruction=long_instruction,
144
+ wrap_lines=wrap_lines,
145
+ raise_keyboard_interrupt=raise_keyboard_interrupt,
146
+ mandatory=mandatory,
147
+ mandatory_message=mandatory_message,
148
+ session_result=session_result,
149
+ )
150
+
151
+ self._float = float_allowed
152
+ self._is_float = Condition(lambda: self._float)
153
+ self._max = max_allowed
154
+ self._min = min_allowed
155
+ self._value_error_message = "Remove any non-integer value"
156
+ self._decimal_symbol = decimal_symbol
157
+ self._whole_replace = False
158
+ self._integral_replace = False
159
+ self._replace_mode = replace_mode
160
+
161
+ self._leading_zero_pattern = re.compile(r"^(0*)[0-9]+.*")
162
+ self._sn_pattern = re.compile(r"^.*E-.*")
163
+ self._no_default = False
164
+
165
+ if default is None:
166
+ default = 0
167
+ self._no_default = True
168
+
169
+ if isinstance(default, Callable):
170
+ default = cast(Callable, default)(session_result)
171
+ if self._float:
172
+ default = Decimal(str(float(cast(int, default))))
173
+ if self._float:
174
+ if not isinstance(default, float) and not isinstance(default, Decimal):
175
+ raise InvalidArgument(
176
+ f"{type(self).__name__} argument 'default' should return type of float or Decimal"
177
+ )
178
+ elif not isinstance(default, int):
179
+ raise InvalidArgument(
180
+ f"{type(self).__name__} argument 'default' should return type of int"
181
+ )
182
+ self._default = default
183
+
184
+ if keybindings is None:
185
+ keybindings = {}
186
+ self.kb_maps = {
187
+ "down": [
188
+ {"key": "down"},
189
+ {"key": "c-n", "filter": ~self._is_vim_edit},
190
+ {"key": "j", "filter": self._is_vim_edit},
191
+ ],
192
+ "up": [
193
+ {"key": "up"},
194
+ {"key": "c-p", "filter": ~self._is_vim_edit},
195
+ {"key": "k", "filter": self._is_vim_edit},
196
+ ],
197
+ "left": [
198
+ {"key": "left"},
199
+ {"key": "c-b", "filter": ~self._is_vim_edit},
200
+ {"key": "h", "filter": self._is_vim_edit},
201
+ ],
202
+ "right": [
203
+ {"key": "right"},
204
+ {"key": "c-f", "filter": ~self._is_vim_edit},
205
+ {"key": "l", "filter": self._is_vim_edit},
206
+ ],
207
+ "dot": [{"key": "."}],
208
+ "focus": [{"key": Keys.Tab}, {"key": "s-tab"}],
209
+ "input": [{"key": str(i)} for i in range(10)],
210
+ "negative_toggle": [{"key": "-"}],
211
+ **keybindings,
212
+ }
213
+ self.kb_func_lookup = {
214
+ "down": [{"func": self._handle_down}],
215
+ "up": [{"func": self._handle_up}],
216
+ "left": [{"func": self._handle_left}],
217
+ "right": [{"func": self._handle_right}],
218
+ "focus": [{"func": self._handle_focus}],
219
+ "input": [{"func": self._handle_input}],
220
+ "negative_toggle": [{"func": self._handle_negative_toggle}],
221
+ "dot": [{"func": self._handle_dot}],
222
+ }
223
+
224
+ @self.register_kb(Keys.Any)
225
+ def _(_):
226
+ pass
227
+
228
+ self._whole_width = 1
229
+ self._whole_buffer = Buffer(
230
+ on_text_changed=self._on_whole_text_change,
231
+ on_cursor_position_changed=self._on_cursor_position_change,
232
+ )
233
+
234
+ self._integral_width = 1
235
+ self._integral_buffer = Buffer(
236
+ on_text_changed=self._on_integral_text_change,
237
+ on_cursor_position_changed=self._on_cursor_position_change,
238
+ )
239
+
240
+ self._whole_window = Window(
241
+ height=LayoutDimension.exact(1) if not self._wrap_lines else None,
242
+ content=BufferControl(
243
+ buffer=self._whole_buffer,
244
+ lexer=SimpleLexer("class:input"),
245
+ ),
246
+ width=lambda: Dimension(
247
+ min=self._whole_width,
248
+ max=self._whole_width,
249
+ preferred=self._whole_width,
250
+ ),
251
+ dont_extend_width=True,
252
+ )
253
+
254
+ self._integral_window = Window(
255
+ height=LayoutDimension.exact(1) if not self._wrap_lines else None,
256
+ content=BufferControl(
257
+ buffer=self._integral_buffer,
258
+ lexer=SimpleLexer("class:input"),
259
+ ),
260
+ width=lambda: Dimension(
261
+ min=self._integral_width,
262
+ max=self._integral_width,
263
+ preferred=self._integral_width,
264
+ ),
265
+ )
266
+
267
+ self._layout = Layout(
268
+ HSplit(
269
+ [
270
+ VSplit(
271
+ [
272
+ Window(
273
+ height=(
274
+ LayoutDimension.exact(1)
275
+ if not self._wrap_lines
276
+ else None
277
+ ),
278
+ content=FormattedTextControl(self._get_prompt_message),
279
+ wrap_lines=self._wrap_lines,
280
+ dont_extend_height=True,
281
+ dont_extend_width=True,
282
+ ),
283
+ ConditionalContainer(self._whole_window, filter=~IsDone()),
284
+ ConditionalContainer(
285
+ Window(
286
+ height=(
287
+ LayoutDimension.exact(1)
288
+ if not self._wrap_lines
289
+ else None
290
+ ),
291
+ content=FormattedTextControl(
292
+ [("", self._decimal_symbol)]
293
+ ),
294
+ wrap_lines=self._wrap_lines,
295
+ dont_extend_height=True,
296
+ dont_extend_width=True,
297
+ ),
298
+ filter=self._is_float & ~IsDone(),
299
+ ),
300
+ ConditionalContainer(
301
+ self._integral_window, filter=self._is_float & ~IsDone()
302
+ ),
303
+ ],
304
+ align=HorizontalAlign.LEFT,
305
+ ),
306
+ ConditionalContainer(
307
+ Window(content=DummyControl()),
308
+ filter=~IsDone() & self._is_displaying_long_instruction,
309
+ ),
310
+ ValidationWindow(
311
+ invalid_message=self._get_error_message,
312
+ filter=self._is_invalid & ~IsDone(),
313
+ wrap_lines=self._wrap_lines,
314
+ ),
315
+ InstructionWindow(
316
+ message=self._long_instruction,
317
+ filter=~IsDone() & self._is_displaying_long_instruction,
318
+ wrap_lines=self._wrap_lines,
319
+ ),
320
+ ]
321
+ ),
322
+ )
323
+
324
+ self.focus = self._whole_window
325
+
326
+ self._application = Application(
327
+ layout=self._layout,
328
+ style=self._style,
329
+ key_bindings=self._kb,
330
+ after_render=self._after_render,
331
+ editing_mode=self._editing_mode,
332
+ )
333
+
334
+ def _fix_sn(self, value: str) -> Tuple[str, str]:
335
+ """Fix sciencetific notation format.
336
+
337
+ Args:
338
+ value: Value to fix.
339
+
340
+ Returns:
341
+ A tuple of whole buffer text and integral buffer text.
342
+ """
343
+ left, right = value.split("E-")
344
+ whole_buffer_text = "0"
345
+ integral_buffer_text = f"{(int(right) - 1) * '0'}{left.replace('.', '')}"
346
+ return whole_buffer_text, integral_buffer_text
347
+
348
+ def _on_rendered(self, _) -> None:
349
+ """Additional processing to adjust buffer content after render."""
350
+ if self._no_default:
351
+ return
352
+ if not self._float:
353
+ self._whole_buffer.text = str(self._default)
354
+ self._integral_buffer.text = "0"
355
+ else:
356
+ if self._sn_pattern.match(str(self._default)) is None:
357
+ whole_buffer_text, integral_buffer_text = str(self._default).split(".")
358
+ else:
359
+ whole_buffer_text, integral_buffer_text = self._fix_sn(
360
+ str(self._default)
361
+ )
362
+ self._integral_buffer.text = integral_buffer_text
363
+ self._whole_buffer.text = whole_buffer_text
364
+ self._whole_buffer.cursor_position = len(self._whole_buffer.text)
365
+ self._integral_buffer.cursor_position = len(self._integral_buffer.text)
366
+ if self._replace_mode:
367
+ # check to start replace mode if applicable
368
+ if self._whole_buffer.text == "0":
369
+ self._whole_replace = True
370
+ self._whole_buffer.cursor_position = 0
371
+ if self._integral_buffer.text == "0":
372
+ self._integral_replace = True
373
+ self._integral_buffer.cursor_position = 0
374
+
375
+ def _handle_number(self, increment: bool) -> None:
376
+ """Handle number increment and decrement.
377
+
378
+ Additional processing to handle leading zeros in integral buffer
379
+ as well as SN notation.
380
+
381
+ Args:
382
+ increment: Indicate if the operation should increment or decrement.
383
+ """
384
+ if self.buffer_replace:
385
+ self.buffer_replace = False
386
+ self.focus_buffer.cursor_position += 1
387
+ try:
388
+ leading_zeros = ""
389
+ if self.focus_buffer == self._integral_buffer:
390
+ zeros = self._leading_zero_pattern.match(self._integral_buffer.text)
391
+ if zeros is not None:
392
+ leading_zeros = zeros.group(1)
393
+ current_text_len = len(self.focus_buffer.text)
394
+ if not self.focus_buffer.text:
395
+ next_text = "0"
396
+ next_text_len = 1
397
+ else:
398
+ if not increment:
399
+ if (
400
+ self.focus_buffer == self._integral_buffer
401
+ and int(self.focus_buffer.text) == 0
402
+ ):
403
+ return
404
+ next_text = leading_zeros + str(int(self.focus_buffer.text) - 1)
405
+ else:
406
+ next_text = leading_zeros + str(int(self.focus_buffer.text) + 1)
407
+ next_text_len = len(next_text)
408
+ desired_position = (
409
+ self.focus_buffer.cursor_position + next_text_len - current_text_len
410
+ )
411
+ self.focus_buffer.cursor_position = desired_position
412
+ self.focus_buffer.text = next_text
413
+ if self.focus_buffer.cursor_position != desired_position:
414
+ self.focus_buffer.cursor_position = desired_position
415
+ except ValueError:
416
+ self._set_error(message=self._value_error_message)
417
+
418
+ def _handle_down(self, _) -> None:
419
+ """Handle down key press."""
420
+ self._handle_number(increment=False)
421
+
422
+ def _handle_up(self, _) -> None:
423
+ """Handle up key press."""
424
+ self._handle_number(increment=True)
425
+
426
+ def _handle_left(self, _) -> None:
427
+ """Handle left key press.
428
+
429
+ Move to the left by one cursor position and focus the whole window
430
+ if applicable.
431
+ """
432
+ self.buffer_replace = False
433
+ if (
434
+ self.focus == self._integral_window
435
+ and self.focus_buffer.cursor_position == 0
436
+ ):
437
+ self.focus = self._whole_window
438
+ else:
439
+ self.focus_buffer.cursor_position -= 1
440
+
441
+ def _handle_right(self, _) -> None:
442
+ """Handle right key press.
443
+
444
+ Move to the right by one cursor position and focus the integral window
445
+ if applicable.
446
+ """
447
+ self.buffer_replace = False
448
+ if (
449
+ self.focus == self._whole_window
450
+ and self.focus_buffer.cursor_position == len(self.focus_buffer.text)
451
+ and self._float
452
+ ):
453
+ self.focus = self._integral_window
454
+ else:
455
+ self.focus_buffer.cursor_position += 1
456
+
457
+ def _handle_enter(self, event: "KeyPressEvent") -> None:
458
+ """Handle enter event and answer/close the prompt."""
459
+ if not self._float and not self._whole_buffer.text:
460
+ result = ""
461
+ elif (
462
+ self._float
463
+ and not self._whole_buffer.text
464
+ and not self._integral_buffer.text
465
+ ):
466
+ result = ""
467
+ else:
468
+ result = str(self.value)
469
+
470
+ try:
471
+ fake_document = FakeDocument(result)
472
+ self._validator.validate(fake_document) # type: ignore
473
+ except ValidationError as e:
474
+ self._set_error(str(e))
475
+ else:
476
+ self.status["answered"] = True
477
+ self.status["result"] = result
478
+ event.app.exit(result=result)
479
+
480
+ def _handle_dot(self, _) -> None:
481
+ """Focus the integral window if `float_allowed`."""
482
+ self._handle_focus(_, self._integral_window)
483
+
484
+ def _handle_focus(self, _, window: Optional[Window] = None) -> None:
485
+ """Focus either the integral window or whole window."""
486
+ if not self._float:
487
+ return
488
+ if window is not None:
489
+ self.focus = window
490
+ return
491
+ if self.focus == self._whole_window:
492
+ self.focus = self._integral_window
493
+ else:
494
+ self.focus = self._whole_window
495
+
496
+ def _handle_input(self, event: "KeyPressEvent") -> None:
497
+ """Handle user input of numbers.
498
+
499
+ Buffer will start as replace mode if the value is zero, once
500
+ cursor is moved or content is changed, disable replace mode.
501
+ """
502
+ if self.buffer_replace:
503
+ self.buffer_replace = False
504
+ self.focus_buffer.text = event.key_sequence[0].data
505
+ self.focus_buffer.cursor_position += 1
506
+ else:
507
+ self.focus_buffer.insert_text(event.key_sequence[0].data)
508
+
509
+ def _handle_negative_toggle(self, _) -> None:
510
+ """Toggle negativity of the prompt value.
511
+
512
+ Force the `-` sign at the start.
513
+ """
514
+ if self._whole_buffer.text == "-":
515
+ self._whole_buffer.text = "0"
516
+ return
517
+ if self._whole_buffer.text.startswith("-"):
518
+ move_cursor = self._whole_buffer.cursor_position < len(
519
+ self._whole_buffer.text
520
+ )
521
+ self._whole_buffer.text = self._whole_buffer.text[1:]
522
+ if move_cursor:
523
+ self._whole_buffer.cursor_position -= 1
524
+ else:
525
+ move_cursor = self._whole_buffer.cursor_position != 0
526
+ self._whole_buffer.text = f"-{self._whole_buffer.text}"
527
+ if move_cursor:
528
+ self._whole_buffer.cursor_position += 1
529
+
530
+ def _on_whole_text_change(self, buffer: Buffer) -> None:
531
+ """Handle event of text changes in buffer."""
532
+ self._whole_width = len(buffer.text) + 1
533
+ self._on_text_change(buffer)
534
+
535
+ def _on_integral_text_change(self, buffer: Buffer) -> None:
536
+ """Handle event of text changes in buffer."""
537
+ self._integral_width = len(buffer.text) + 1
538
+ self._on_text_change(buffer)
539
+
540
+ def _on_text_change(self, buffer: Buffer) -> None:
541
+ """Disable replace mode and fix cursor position on text changes."""
542
+ self.buffer_replace = False
543
+ if buffer.text and buffer.text != "-":
544
+ self.value = self.value
545
+ if buffer.text.startswith("-") and buffer.cursor_position == 0:
546
+ buffer.cursor_position = 1
547
+
548
+ def _on_cursor_position_change(self, buffer: Buffer) -> None:
549
+ """Fix cursor position on cursor movement."""
550
+ if self.focus_buffer.text.startswith("-") and buffer.cursor_position == 0:
551
+ buffer.cursor_position = 1
552
+
553
+ @property
554
+ def buffer_replace(self) -> bool:
555
+ """bool: Current buffer replace mode."""
556
+ if self.focus_buffer == self._whole_buffer:
557
+ return self._whole_replace
558
+ else:
559
+ return self._integral_replace
560
+
561
+ @buffer_replace.setter
562
+ def buffer_replace(self, value) -> None:
563
+ if self.focus_buffer == self._whole_buffer:
564
+ self._whole_replace = value
565
+ else:
566
+ self._integral_replace = value
567
+
568
+ @property
569
+ def focus_buffer(self) -> Buffer:
570
+ """Buffer: Current editable buffer."""
571
+ if self.focus == self._whole_window:
572
+ return self._whole_buffer
573
+ else:
574
+ return self._integral_buffer
575
+
576
+ @property
577
+ def focus(self) -> Window:
578
+ """Window: Current focused window."""
579
+ return self._focus
580
+
581
+ @focus.setter
582
+ def focus(self, value: Window) -> None:
583
+ self._focus = value
584
+ self._layout.focus(self._focus)
585
+
586
+ @property
587
+ def value(self) -> Union[int, float, Decimal]:
588
+ """Union[int, float]: The actual value of the prompt, combining and transforming all input buffer values."""
589
+ try:
590
+ if not self._float:
591
+ return int(self._whole_buffer.text)
592
+ else:
593
+ return Decimal(
594
+ f"{self._whole_buffer.text}.{self._integral_buffer.text if self._integral_buffer.text else 0}"
595
+ )
596
+ except ValueError:
597
+ self._set_error(self._value_error_message)
598
+ return self._default
599
+
600
+ @value.setter
601
+ def value(self, value: Union[int, float, Decimal]) -> None:
602
+ if self._min is not None:
603
+ value = max(
604
+ value, self._min if not self._float else Decimal(str(self._min))
605
+ )
606
+ if self._max is not None:
607
+ value = min(
608
+ value, self._max if not self._float else Decimal(str(self._max))
609
+ )
610
+ if not self._float:
611
+ self._whole_buffer.text = str(value)
612
+ else:
613
+ if self._sn_pattern.match(str(value)) is None:
614
+ whole_buffer_text, integral_buffer_text = str(value).split(".")
615
+ else:
616
+ whole_buffer_text, integral_buffer_text = self._fix_sn(str(value))
617
+
618
+ if self._whole_buffer.text:
619
+ self._whole_buffer.text = whole_buffer_text
620
+ if self._integral_buffer.text:
621
+ self._integral_buffer.text = integral_buffer_text