Belle II Software  release-08-01-10
writer.py
1 # MIT License
2 # Copyright (c) 2016 Western Digital Corporation
3 
4 # Permission is hereby granted, free of charge, to any person obtaining a copy
5 # of this software and associated documentation files (the "Software"), to deal
6 # in the Software without restriction, including without limitation the rights
7 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 # copies of the Software, and to permit persons to whom the Software is
9 # furnished to do so, subject to the following conditions:
10 
11 # The above copyright notice and this permission notice shall be included in all
12 # copies or substantial portions of the Software.
13 
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 # SOFTWARE.
21 
22 """Write Value Change Dump files.
23 
24 This module provides :class:`VCDWriter` for writing VCD files.
25 
26 """
27 from __future__ import print_function
28 from collections import OrderedDict, Sequence
29 from numbers import Number
30 import datetime
31 
32 import six
33 from six.moves import zip, zip_longest
34 
35 
36 class VCDPhaseError(Exception):
37  """Indicating a :class:`VCDWriter` method was called in the wrong phase.
38 
39  For example, calling :meth:`register_var()` after :meth:`close()` will
40  raise this exception.
41 
42  """
43 
44 
45 class VCDWriter(object):
46  """Value Change Dump writer.
47 
48  A VCD file captures time-ordered changes to the value of variables.
49 
50  :param file file: A file-like object to write the VCD data.
51  :param timescale:
52  Scale of the VCD timestamps. The timescale may either be a string or a
53  tuple containing an (int, str) pair.
54  :type timescale: str, tuple
55  :param str date: Optional `$date` string used in the VCD header.
56  :param str comment: Optional `$comment` string used in the VCD header.
57  :param str version: Optional `$version` string used in the VCD header.
58  :param str default_scope_type: Scope type for scopes where
59  :meth:`set_scope_type()` is not called explicitly.
60  :param str scope_sep: Separator for scopes specified as strings.
61  :param int init_timestamp: The initial timestamp. default=0
62  :raises ValueError: for invalid timescale values
63 
64  """
65 
66 
67  SCOPE_TYPES = ['begin', 'fork', 'function', 'module', 'task']
68 
69 
70  VAR_TYPES = ['event', 'integer', 'parameter', 'real', 'realtime', 'reg',
71  'supply0', 'supply1', 'time', 'tri', 'triand', 'trior',
72  'trireg', 'tri0', 'tri1', 'wand', 'wire', 'wor']
73 
74 
75  TIMESCALE_NUMS = [1, 10, 100]
76 
77 
78  TIMESCALE_UNITS = ['s', 'ms', 'us', 'ns', 'ps', 'fs']
79 
80  def __init__(self, file, timescale='1 us', date=None, comment='',
81  version='', default_scope_type='module', scope_sep='.',
82  check_values=True, init_timestamp=0):
83  """Initialization of VCDWriter"""
84 
85  self._ofile_ofile = file
86 
87  self._header_keywords_header_keywords = {
88  '$timescale': self._check_timescale_check_timescale(timescale),
89  '$date': str(datetime.datetime.now()) if date is None else date,
90  '$comment': comment,
91  '$version': version,
92  }
93  if default_scope_type not in self.SCOPE_TYPESSCOPE_TYPES:
94  raise ValueError('Invalid default scope type ({})'.format(
95  default_scope_type))
96 
97  self._default_scope_type_default_scope_type = default_scope_type
98 
99  self._scope_sep_scope_sep = scope_sep
100 
101  self._check_values_check_values = check_values
102 
103  self._registering_registering = True
104 
105  self._closed_closed = False
106 
107  self._dumping_dumping = True
108 
109  self._next_var_id_next_var_id = 0
110 
111  self._scope_var_strs_scope_var_strs = {}
112 
113  self._scope_var_names_scope_var_names = {}
114 
115  self._scope_types_scope_types = {}
116 
117  self._ident_values_ident_values = OrderedDict()
118 
119  self._timestamp_timestamp = int(init_timestamp)
120 
121  def set_scope_type(self, scope, scope_type):
122  """Set the scope_type for a given scope.
123 
124  The scope's type may be set to one of the valid :const:`SCOPE_TYPES`.
125  VCD viewer applications may display different scope types differently.
126 
127  :param scope: The scope to set the type of.
128  :type scope: str or sequence of str
129  :param str scope_type: A valid scope type string.
130  :raises ValueError: for invalid `scope_type`
131 
132  """
133  if scope_type is not None and scope_type not in self.SCOPE_TYPESSCOPE_TYPES:
134  raise ValueError('Invalid scope_type "{}"'.format(scope_type))
135  scope_tuple = self._get_scope_tuple_get_scope_tuple(scope)
136  self._scope_types_scope_types[scope_tuple] = scope_type
137 
138  def register_var(self, scope, name, var_type, size=None, init=None,
139  ident=None):
140  """Register a VCD variable and return function to change value.
141 
142  All VCD variables must be registered prior to any value changes.
143 
144  .. Note::
145 
146  The variable `name` differs from the variable's `ident`
147  (identifier). The `name` (also known as `ref`) is meant to refer to
148  the variable name in the code being traced and is visible in VCD
149  viewer applications. The `ident`, however, is only used within the
150  VCD file and can be auto-generated (by specifying ``ident=None``)
151  for most applications.
152 
153  :param scope: The hierarchical scope that the variable belongs within.
154  :type scope: str or sequence of str
155  :param str name: Name of the variable.
156  :param str var_type: One of :const:`VAR_TYPES`.
157  :param size:
158  Size, in bits, of the variable. The *size* may be expressed as an
159  int or, for vector variable types, a tuple of int. When the size is
160  expressed as a tuple, the *value* passed to :meth:`change()` must
161  also be a tuple of same arity as the *size* tuple. Some variable
162  types ('integer', 'real', 'realtime', and 'event') have a default
163  size and thus *size* may be ``None`` for those variable types.
164  :type size: int or tuple(int) or None
165  :param init: Optional initial value; defaults to 'x'.
166  :param str ident: Optional identifier for use in the VCD stream.
167  :raises VCDPhaseError: if any values have been changed
168  :raises ValueError: for invalid var_type value
169  :raises TypeError: for invalid parameter types
170  :raises KeyError: for duplicate var name
171  :returns: :class:`Variable` instance appropriate for use with
172  :meth:`change()`.
173 
174  """
175  if self._closed_closed:
176  raise VCDPhaseError('Cannot register after close().')
177  elif not self._registering_registering:
178  raise VCDPhaseError('Cannot register after time 0.')
179  elif var_type not in self.VAR_TYPESVAR_TYPES:
180  raise ValueError('Invalid var_type "{}"'.format(var_type))
181 
182  scope_tuple = self._get_scope_tuple_get_scope_tuple(scope)
183 
184  scope_names = self._scope_var_names_scope_var_names.setdefault(scope_tuple, [])
185  if name in scope_names:
186  raise KeyError('Duplicate var {} in scope {}'.format(name, scope))
187 
188  if ident is None:
189  ident = format(self._next_var_id_next_var_id, 'x')
190 
191  if size is None:
192  if var_type in ['integer', 'real', 'realtime']:
193  size = 64
194  elif var_type == 'event':
195  size = 1
196  else:
197  raise ValueError(
198  'Must supply size for {} var_type'.format(var_type))
199 
200  if isinstance(size, Sequence):
201  size = tuple(size)
202  var_size = sum(size)
203  else:
204  var_size = size
205 
206  var_str = '$var {var_type} {size} {ident} {name} $end'.format(
207  var_type=var_type, size=var_size, ident=ident, name=name)
208 
209  if init is None:
210  if var_type == 'real':
211  init = 0.0
212  elif isinstance(size, tuple):
213  init = tuple('x' * len(size))
214  else:
215  init = 'x'
216 
217  if size == 1:
218  var = ScalarVariable(ident, var_type, size)
219  elif var_type == 'real':
220  var = RealVariable(ident, var_type, size)
221  else:
222  var = VectorVariable(ident, var_type, size)
223 
224  if var_type != 'event':
225  self.changechange(var, self._timestamp_timestamp, init)
226 
227  # Only alter state after change_func() succeeds
228  self._next_var_id_next_var_id += 1
229  self._scope_var_strs_scope_var_strs.setdefault(scope_tuple, []).append(var_str)
230  scope_names.append(name)
231 
232  return var
233 
234  def dump_off(self, timestamp):
235  """Suspend dumping to VCD file."""
236  if self._dumping_dumping and not self._registering_registering and self._ident_values_ident_values:
237  """set dump_off"""
238  self._dump_off_dump_off(timestamp)
239  self._dumping_dumping = False
240 
241  def _dump_off(self, timestamp):
242  """Stop dumping to VCD file."""
243  print('#' + str(int(timestamp)), file=self._ofile_ofile)
244  print('$dumpoff', file=self._ofile_ofile)
245  for ident, val_str in six.iteritems(self._ident_values_ident_values):
246  if val_str[0] == 'b':
247  print('bx', ident, file=self._ofile_ofile)
248  elif val_str[0] == 'r':
249  pass # real variables cannot have 'z' or 'x' state
250  else:
251  print('x', ident, sep='', file=self._ofile_ofile)
252  print('$end', file=self._ofile_ofile)
253 
254  def dump_on(self, timestamp):
255  """Resume dumping to VCD file."""
256  if not self._dumping_dumping and not self._registering_registering and self._ident_values_ident_values:
257  print('#' + str(int(timestamp)), file=self._ofile_ofile)
258  """set dump_values"""
259  self._dump_values_dump_values('$dumpon')
260  self._dumping_dumping = True
261 
262  def _dump_values(self, keyword):
263  """Dump values to VCD file."""
264  print(keyword, file=self._ofile_ofile)
265  # TODO: events should be excluded
266  print(*six.itervalues(self._ident_values_ident_values),
267  sep='\n', file=self._ofile_ofile)
268  print('$end', file=self._ofile_ofile)
269 
270  def change(self, var, timestamp, value):
271  """Change variable's value in VCD stream.
272 
273  This is the fundamental behavior of a :class:`VCDWriter` instance. Each
274  time a variable's value changes, this method should be called.
275 
276  The *timestamp* must be in-order relative to timestamps from previous
277  calls to :meth:`change()`. It is okay to call :meth:`change()` multiple
278  times with the same *timestamp*, but never with a past *timestamp*.
279 
280  .. Note::
281 
282  :meth:`change()` may be called multiple times before the timestamp
283  progresses past 0. The last value change for each variable will go
284  into the $dumpvars section.
285 
286  :param Variable var: :class:`Variable` instance (i.e. from
287  :meth:`register_var()`).
288  :param int timestamp: Current simulation time.
289  :param value:
290  New value for *var*. For :class:`VectorVariable`, if the variable's
291  *size* is a tuple, then *value* must be a tuple of the same arity.
292 
293  :raises ValueError: if the value is not valid for *var*.
294  :raises VCDPhaseError: if the timestamp is out of order or the
295  :class:`VCDWriter` instance is closed.
296 
297  """
298  if timestamp < self._timestamp_timestamp:
299  raise VCDPhaseError('Out of order value change ({})'.format(var))
300  elif self._closed_closed:
301  raise VCDPhaseError('Cannot change value after close()')
302 
303  val_str = var.format_value(value, self._check_values_check_values)
304  ts_int = int(timestamp)
305 
306  if ts_int > self._timestamp_timestamp:
307  if self._registering_registering:
308  self._finalize_registration_finalize_registration()
309  if self._dumping_dumping:
310  print('#', ts_int, sep='', file=self._ofile_ofile)
311  self._timestamp_timestamp = ts_int
312 
313  if self._dumping_dumping and not self._registering_registering:
314  print(val_str, file=self._ofile_ofile)
315  else:
316  self._ident_values_ident_values[var.ident] = val_str
317 
318  def _get_scope_tuple(self, scope):
319  """get scope tuple function of the VCDWrite"""
320  if isinstance(scope, six.string_types):
321  return tuple(scope.split(self._scope_sep_scope_sep))
322  if isinstance(scope, (list, tuple)):
323  return tuple(scope)
324  else:
325  raise TypeError('Invalid scope {}'.format(scope))
326 
327  @classmethod
328  def _check_timescale(cls, timescale):
329  """check time scale function of the VCDWrite"""
330  if isinstance(timescale, (list, tuple)):
331  if len(timescale) == 1:
332  num_str = '1'
333  unit = timescale[0]
334  elif len(timescale) == 2:
335  num, unit = timescale
336  if num not in cls.TIMESCALE_NUMSTIMESCALE_NUMS:
337  raise ValueError('Invalid timescale num {}'.format(num))
338  num_str = str(num)
339  else:
340  raise ValueError('Invalid timescale {}'.format(timescale))
341  elif isinstance(timescale, six.string_types):
342  if timescale in cls.TIMESCALE_UNITSTIMESCALE_UNITS:
343  num_str = '1'
344  unit = timescale
345  else:
346  for num in sorted(cls.TIMESCALE_NUMSTIMESCALE_NUMS, reverse=True):
347  num_str = str(num)
348  if timescale.startswith(num_str):
349  unit = timescale[len(num_str):].lstrip(' ')
350  break
351  else:
352  raise ValueError(
353  'Invalid timescale num {}'.format(timescale))
354  else:
355  raise TypeError('Invalid timescale type {}'
356  .format(type(timescale).__name__))
357  if unit not in cls.TIMESCALE_UNITSTIMESCALE_UNITS:
358  raise ValueError('Invalid timescale unit "{}"'.format(unit))
359  return ' '.join([num_str, unit])
360 
361  def __enter__(self):
362  """enter of VCDWriter"""
363  return self
364 
365  def __exit__(self, exc_type, exc_val, exc_tb):
366  """exit of VCDWriter"""
367  self.closeclose()
368 
369  def close(self, timestamp=None):
370  """Close VCD writer.
371 
372  Any buffered VCD data is flushed to the output file. After
373  :meth:`close()`, no variable registration or value changes will be
374  accepted.
375 
376  :param int timestamp: optional final timestamp to insert into VCD
377  stream.
378 
379  .. Note::
380 
381  The output file is not automatically closed. It is up to the user
382  to ensure the output file is closed after the :class:`VCDWriter`
383  instance is closed.
384 
385  """
386  if not self._closed_closed:
387  self.flushflush(timestamp)
388  self._closed_closed = True
389 
390  def flush(self, timestamp=None):
391  """Flush any buffered VCD data to output file.
392 
393  If the VCD header has not already been written, calling `flush()` will
394  force the header to be written thus disallowing any further variable
395  registration.
396 
397  :param int timestamp: optional timestamp to insert into VCD stream.
398 
399  """
400  if self._closed_closed:
401  raise VCDPhaseError('Cannot flush() after close()')
402  if self._registering_registering:
403  self._finalize_registration_finalize_registration()
404  if timestamp is not None and timestamp > self._timestamp_timestamp:
405  print("#", int(timestamp), sep='', file=self._ofile_ofile)
406  self._ofile_ofile.flush()
407 
408  def _gen_header(self):
409  """generate header for VCDWriter"""
410  for kwname, kwvalue in sorted(six.iteritems(self._header_keywords_header_keywords)):
411  if not kwvalue:
412  continue
413  lines = kwvalue.split('\n')
414  if len(lines) == 1:
415  yield '{} {} $end'.format(kwname, lines[0])
416  else:
417  yield kwname
418  for line in lines:
419  yield '\t' + line
420  yield '$end'
421 
422  prev_scope = []
423  for scope in sorted(self._scope_var_strs_scope_var_strs):
424  var_strs = self._scope_var_strs_scope_var_strs.pop(scope)
425 
426  for i, (prev, this) in enumerate(zip_longest(prev_scope, scope)):
427  if prev != this:
428  for _ in prev_scope[i:]:
429  yield '$upscope $end'
430 
431  for j, name in enumerate(scope[i:]):
432  scope_type = self._scope_types_scope_types.get(
433  scope[:i + j + 1], self._default_scope_type_default_scope_type)
434  yield '$scope {} {} $end'.format(scope_type, name)
435  break
436  else:
437  assert scope != prev_scope # pragma no cover
438 
439  for var_str in var_strs:
440  yield var_str
441 
442  prev_scope = scope
443 
444  for _ in prev_scope:
445  yield '$upscope $end'
446 
447  yield '$enddefinitions $end'
448 
450  """finalize registration of VCDWriter"""
451  assert self._registering_registering
452  print(*self._gen_header_gen_header(), sep='\n', file=self._ofile_ofile)
453  if self._ident_values_ident_values:
454  print('#' + str(int(self._timestamp_timestamp)), file=self._ofile_ofile)
455  self._dump_values_dump_values('$dumpvars')
456  if not self._dumping_dumping:
457  self._dump_off_dump_off(self._timestamp_timestamp)
458  self._registering_registering = False
459 
460  # This state is not needed after registration phase.
461  self._header_keywords_header_keywords.clear()
462  self._scope_types_scope_types.clear()
463  self._scope_var_names_scope_var_names.clear()
464 
465 
466 class Variable(object):
467  """VCD variable details needed to call :meth:`VCDWriter.change()`."""
468 
469 
470  __slots__ = ('ident', 'type', 'size')
471 
472  def __init__(self, ident, type, size):
473  """Initialization of Variable function"""
474 
475  self.identident = ident
476 
477  self.typetype = type
478 
479  self.sizesize = size
480 
481  def format_value(self, value, check=True):
482  """Format value change for use in VCD stream."""
483  raise NotImplementedError
484 
485 
487  """One-bit VCD scalar.
488 
489  This is a 4-state variable and thus may have values of 0, 1, 'z', or 'x'.
490 
491  """
492 
493 
494  __slots__ = ()
495 
496  def format_value(self, value, check=True):
497  """Format scalar value change for VCD stream.
498 
499  :param value: 1-bit (4-state) scalar value.
500  :type value: str, bool, int, or None
501  :raises ValueError: for invalid *value*.
502  :returns: string representing value change for use in a VCD stream.
503 
504  """
505  if isinstance(value, six.string_types):
506  if check and (len(value) != 1 or value not in '01xzXZ'):
507  raise ValueError('Invalid scalar value ({})'.format(value))
508  return value + self.identident
509  elif value is None:
510  return 'z' + self.identident
511  elif value:
512  return '1' + self.identident
513  else:
514  return '0' + self.identident
515 
516 
518  """Real (IEEE-754 double-precision floating point) variable.
519 
520  Values must be numeric and cannot be 'x' or 'z' states.
521 
522  """
523 
524 
525  __slots__ = ()
526 
527  def format_value(self, value, check=True):
528  """Format real value change for VCD stream.
529 
530  :param value: Numeric changed value.
531  :param type: float or int
532  :raises ValueError: for invalid real *value*.
533  :returns: string representing value change for use in a VCD stream.
534 
535  """
536  if not check or isinstance(value, Number):
537  return 'r{:.16g} {}'.format(value, self.identident)
538  else:
539  raise ValueError('Invalid real value ({})'.format(value))
540 
541 
543  """Bit vector variable type.
544 
545  This is for the various non-scalar and non-real variable types including
546  integer, register, wire, etc.
547 
548  """
549 
550 
551  __slots__ = ()
552 
553  def format_value(self, value, check=True):
554  """Format value change for VCD stream.
555 
556  :param value: New value for the variable.
557  :types value: int, str, or None
558  :raises ValueError: for *some* invalid values.
559 
560  A *value* of `None` is the same as `'z'`.
561 
562  .. Warning::
563 
564  If *value* is of type :py:class:`str`, all characters must be one
565  of `'01xzXZ'`. For the sake of performance, checking **is not**
566  done to ensure value strings only contain conforming characters.
567  Thus it is possible to produce invalid VCD streams with invalid
568  string values.
569 
570  """
571  if isinstance(self.sizesize, tuple):
572  # The string is built-up right-to-left in order to minimize/avoid
573  # left-extension in the final value string.
574  vstr_list = []
575  vstr_len = 0
576  size_sum = 0
577  for i, (v, size) in enumerate(zip(reversed(value),
578  reversed(self.sizesize))):
579  vstr = self._format_value_format_value(v, size, check)
580  if not vstr_list:
581  vstr_list.insert(0, vstr)
582  vstr_len += len(vstr)
583  else:
584  leftc = vstr_list[0][0]
585  rightc = vstr[0]
586  if len(vstr) > 1 or ((rightc != leftc or leftc == '1') and
587  (rightc != '0' or leftc != '1')):
588  extendc = '0' if leftc == '1' else leftc
589  extend_size = size_sum - vstr_len
590  vstr_list.insert(0, extendc * extend_size)
591  vstr_list.insert(0, vstr)
592  vstr_len += extend_size + len(vstr)
593  size_sum += size
594  value_str = ''.join(vstr_list)
595  else:
596  value_str = self._format_value_format_value(value, self.sizesize, check)
597  return 'b{} {}'.format(value_str, self.identident)
598 
599  def _format_value(self, value, size, check):
600  """format value function of VCDWriter"""
601  if isinstance(value, six.integer_types):
602  max_val = 1 << size
603  if check and (-value > (max_val >> 1) or value >= max_val):
604  raise ValueError('Value ({}) not representable in {} bits'
605  .format(value, size))
606  if value < 0:
607  value += max_val
608  return format(value, 'b')
609  elif value is None:
610  return 'z'
611  else:
612  if check and (not isinstance(value, six.string_types) or
613  len(value) > size or
614  any(c not in '01xzXZ-' for c in value)):
615  raise ValueError('Invalid vector value ({})'.format(value))
616  return value
def format_value(self, value, check=True)
Definition: writer.py:527
def format_value(self, value, check=True)
Definition: writer.py:496
_dumping
set dumping
Definition: writer.py:107
_registering
set registering
Definition: writer.py:103
_timestamp
set time_stamp
Definition: writer.py:119
def __exit__(self, exc_type, exc_val, exc_tb)
Definition: writer.py:365
def _gen_header(self)
Definition: writer.py:408
def _check_timescale(cls, timescale)
Definition: writer.py:328
_scope_sep
set scope_sep
Definition: writer.py:99
def _dump_values(self, keyword)
Definition: writer.py:262
def dump_off(self, timestamp)
Definition: writer.py:234
_next_var_id
set next_var_id
Definition: writer.py:109
def _finalize_registration(self)
Definition: writer.py:449
list TIMESCALE_NUMS
Valid timescale numbers.
Definition: writer.py:75
def dump_on(self, timestamp)
Definition: writer.py:254
_scope_types
set scopr_types
Definition: writer.py:115
def change(self, var, timestamp, value)
Definition: writer.py:270
def __init__(self, file, timescale='1 us', date=None, comment='', version='', default_scope_type='module', scope_sep='.', check_values=True, init_timestamp=0)
Definition: writer.py:82
list TIMESCALE_UNITS
Valid timescale units.
Definition: writer.py:78
list VAR_TYPES
Valid VCD variable types.
Definition: writer.py:70
_check_values
set check_values
Definition: writer.py:101
def register_var(self, scope, name, var_type, size=None, init=None, ident=None)
Definition: writer.py:139
_ofile
output file
Definition: writer.py:85
def close(self, timestamp=None)
Definition: writer.py:369
def flush(self, timestamp=None)
Definition: writer.py:390
_scope_var_names
set scope_var_names
Definition: writer.py:113
_default_scope_type
set default_scope_type
Definition: writer.py:97
def _dump_off(self, timestamp)
Definition: writer.py:241
def set_scope_type(self, scope, scope_type)
Definition: writer.py:121
list SCOPE_TYPES
Valid VCD scope types.
Definition: writer.py:67
def _get_scope_tuple(self, scope)
Definition: writer.py:318
_scope_var_strs
set scope_var_strs
Definition: writer.py:111
_ident_values
set ident_values
Definition: writer.py:117
_header_keywords
header keywords
Definition: writer.py:87
ident
Identifier used in VCD output stream.
Definition: writer.py:475
type
VCD variable type; one of :const:VCDWriter.VAR_TYPES.
Definition: writer.py:477
size
Size, in bits, of variable.
Definition: writer.py:479
def __init__(self, ident, type, size)
Definition: writer.py:472
def format_value(self, value, check=True)
Definition: writer.py:481
def _format_value(self, value, size, check)
Definition: writer.py:599
def format_value(self, value, check=True)
Definition: writer.py:553