jk_prettyprintobj 0.2024.6.7__tar.gz → 0.2024.10.20__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jk_prettyprintobj
3
- Version: 0.2024.6.7
3
+ Version: 0.2024.10.20
4
4
  Summary: This python module provides a mixin for creating pretty debugging output for objects. This is especially useful for semi-complex data structures.
5
5
  Keywords: pretty-print,debugging,debug
6
6
  Author-email: Jürgen Knauth <pubsrc@binary-overflow.de>
@@ -0,0 +1,51 @@
1
+
2
+
3
+
4
+
5
+ #
6
+ # Holds settings about how to dump data.
7
+ #
8
+ class DumperSettings(object):
9
+
10
+ ################################################################################################################################
11
+ ## Constants
12
+ ################################################################################################################################
13
+
14
+ ################################################################################################################################
15
+ ## Constructor
16
+ ################################################################################################################################
17
+
18
+ #
19
+ # Constructor method.
20
+ #
21
+ def __init__(self) -> None:
22
+ self.showPrimitivesWithType = False
23
+ self.showDictKeysWithType = False
24
+ self.showComplexStructsWithType = False
25
+ self.compactSequenceLengthLimit = 8
26
+ self.compactSequenceItemLengthLimit = 50
27
+ self.bytesLineSize = 32
28
+ self.compactBytesLinesLengthLimit = 32
29
+ #
30
+
31
+ ################################################################################################################################
32
+ ## Public Properties
33
+ ################################################################################################################################
34
+
35
+ ################################################################################################################################
36
+ ## Helper Methods
37
+ ################################################################################################################################
38
+
39
+ ################################################################################################################################
40
+ ## Public Methods
41
+ ################################################################################################################################
42
+
43
+ ################################################################################################################################
44
+ ## Public Static Methods
45
+ ################################################################################################################################
46
+
47
+ #
48
+
49
+
50
+
51
+
@@ -0,0 +1,47 @@
1
+
2
+
3
+
4
+ #
5
+ # Represents a value that should be written directly without any automatic formatting.
6
+ #
7
+ class RawValue(object):
8
+
9
+ ################################################################################################################################
10
+ ## Constants
11
+ ################################################################################################################################
12
+
13
+ ################################################################################################################################
14
+ ## Constructor
15
+ ################################################################################################################################
16
+
17
+ #
18
+ # Constructor method.
19
+ #
20
+ def __init__(self, text:str) -> None:
21
+ assert isinstance(text, str)
22
+ assert text
23
+
24
+ self.text = text
25
+ #
26
+
27
+ ################################################################################################################################
28
+ ## Public Properties
29
+ ################################################################################################################################
30
+
31
+ ################################################################################################################################
32
+ ## Helper Methods
33
+ ################################################################################################################################
34
+
35
+ ################################################################################################################################
36
+ ## Public Methods
37
+ ################################################################################################################################
38
+
39
+ ################################################################################################################################
40
+ ## Public Static Methods
41
+ ################################################################################################################################
42
+
43
+ #
44
+
45
+
46
+
47
+
@@ -0,0 +1,152 @@
1
+
2
+
3
+ import codecs
4
+ import math
5
+ import typing
6
+
7
+ from .DumperSettings import DumperSettings
8
+
9
+
10
+
11
+
12
+
13
+ class _ByteChunker(object):
14
+
15
+ ################################################################################################################################
16
+ ## Constants
17
+ ################################################################################################################################
18
+
19
+ ################################################################################################################################
20
+ ## Constructor
21
+ ################################################################################################################################
22
+
23
+ ################################################################################################################################
24
+ ## Public Properties
25
+ ################################################################################################################################
26
+
27
+ ################################################################################################################################
28
+ ## Helper Methods
29
+ ################################################################################################################################
30
+
31
+ @staticmethod
32
+ def _x_byteChunkToHex(data:bytes) -> str:
33
+ hexSpanLength = 16 # == 8 bytes for a span
34
+
35
+ s = codecs.encode(data, "hex").decode("ascii")
36
+ chunks = [ s[i:i+hexSpanLength] for i in range(0, len(s), hexSpanLength) ]
37
+ return " ".join(chunks)
38
+ #
39
+
40
+ @staticmethod
41
+ def _x_byteChunkToASCII(data:bytes) -> str:
42
+ spanLength = 8 # == 8 bytes for a span
43
+
44
+ ret = []
45
+ for i, b in enumerate(data):
46
+ if (i % spanLength) == 0:
47
+ ret.append(" ")
48
+ if 32 <= b <= 127:
49
+ ret.append(chr(b))
50
+ else:
51
+ ret.append(".")
52
+
53
+ return "".join(ret)
54
+ #
55
+
56
+ ################################################################################################################################
57
+ ## Public Methods
58
+ ################################################################################################################################
59
+
60
+ ################################################################################################################################
61
+ ## Public Static Methods
62
+ ################################################################################################################################
63
+
64
+ #
65
+ # Creates data for output.
66
+ #
67
+ # @param DumperSettings settings The settings object that contains <c>settings.compactBytesLinesLengthLimit</c>
68
+ # @param bytes data The full data block to process
69
+ # @param str? processorName Understands "shorten" to provide shortened output,
70
+ # respecting <c>settings.compactBytesLinesLengthLimit</c> in that cae
71
+ # @return tuple<str,str,str>[] Returns a generator that provides tuples of the following values:
72
+ # * str offset part
73
+ # * str hex data part
74
+ # * str ascii data part
75
+ #
76
+ @staticmethod
77
+ def chunkWithOfs(settings:DumperSettings, data:bytes, processorName:str = None) -> typing.Generator[typing.Tuple[str,str,str],typing.Tuple[str,str,str],typing.Tuple[str,str,str]]:
78
+ assert isinstance(settings, DumperSettings)
79
+ assert isinstance(data, bytes)
80
+ chunkSize = settings.bytesLineSize
81
+ assert isinstance(chunkSize, int)
82
+ assert chunkSize > 0
83
+ hexStrPadded = chunkSize*2 + math.ceil(chunkSize / 8) - 1
84
+ if processorName is not None:
85
+ assert isinstance(processorName, str)
86
+
87
+ # ----
88
+
89
+ nTotalLength = len(data)
90
+ nTotalLines = math.ceil(nTotalLength / chunkSize)
91
+ formatStrFragment = None
92
+ formatStrFragmentEllipsis = None
93
+ if nTotalLength <= 256*256:
94
+ formatStrFragment = "{:04x}"
95
+ formatStrFragmentEllipsis = "... "
96
+ elif nTotalLength <= 256*256*256:
97
+ formatStrFragment = "{:06x}"
98
+ formatStrFragmentEllipsis = "... "
99
+ else:
100
+ formatStrFragment = "{:08x}"
101
+ formatStrFragmentEllipsis = "... "
102
+
103
+ # ----
104
+
105
+ skipFrom = -1
106
+ skipTo = -1
107
+ if processorName:
108
+ if processorName == "shorten":
109
+ skipFrom = settings.compactBytesLinesLengthLimit
110
+ skipTo = nTotalLines - 4
111
+ if skipFrom >= skipTo:
112
+ skipFrom = -1
113
+ skipTo = -1
114
+ else:
115
+ raise Exception("No such postprocessor: " + repr(processorName))
116
+
117
+ # ----
118
+
119
+ if skipFrom < 0:
120
+ # direct loop, no addtional if statements
121
+ iFrom = 0
122
+ iTo = chunkSize
123
+ while iFrom < len(data):
124
+ chunk = data[iFrom:iTo]
125
+ yield formatStrFragment.format(iFrom), _ByteChunker._x_byteChunkToHex(chunk).ljust(hexStrPadded), _ByteChunker._x_byteChunkToASCII(chunk)
126
+ iFrom = iTo
127
+ iTo += chunkSize
128
+ else:
129
+ # loop with if statements
130
+ lineNo = 0
131
+ iFrom = 0
132
+ iTo = chunkSize
133
+ while iFrom < len(data):
134
+ chunk = data[iFrom:iTo]
135
+ if skipFrom <= lineNo <= skipTo:
136
+ if skipFrom == lineNo:
137
+ yield formatStrFragmentEllipsis, "...".ljust(hexStrPadded), "..."
138
+ else:
139
+ yield formatStrFragment.format(iFrom), _ByteChunker._x_byteChunkToHex(chunk).ljust(hexStrPadded), _ByteChunker._x_byteChunkToASCII(chunk)
140
+ iFrom = iTo
141
+ iTo += chunkSize
142
+ lineNo += 1
143
+ #
144
+
145
+ #
146
+
147
+
148
+
149
+
150
+
151
+
152
+
@@ -0,0 +1,116 @@
1
+
2
+
3
+ import typing
4
+
5
+ from ._Hex import _Hex
6
+ from ._Bits import _Bits
7
+
8
+
9
+
10
+
11
+
12
+ class _ConverterFunctions(object):
13
+
14
+ ################################################################################################################################
15
+ ## Constants
16
+ ################################################################################################################################
17
+
18
+ ################################################################################################################################
19
+ ## Constructor
20
+ ################################################################################################################################
21
+
22
+ ################################################################################################################################
23
+ ## Public Properties
24
+ ################################################################################################################################
25
+
26
+ ################################################################################################################################
27
+ ## Helper Methods
28
+ ################################################################################################################################
29
+
30
+ ################################################################################################################################
31
+ ## Public Methods
32
+ ################################################################################################################################
33
+
34
+ ################################################################################################################################
35
+ ## Public Static Methods
36
+ ################################################################################################################################
37
+
38
+ @staticmethod
39
+ def str_shortenText(text:str) -> str:
40
+ if len(text) > 40:
41
+ return text[:40] + "..."
42
+ else:
43
+ return text
44
+ #
45
+
46
+ @staticmethod
47
+ def float_roundTo7FractionDigits(data:typing.Union[int,float]) -> float:
48
+ return round(data, 7)
49
+ #
50
+
51
+ @staticmethod
52
+ def float_roundTo6FractionDigits(data:typing.Union[int,float]) -> float:
53
+ return round(data, 6)
54
+ #
55
+
56
+ @staticmethod
57
+ def float_roundTo5FractionDigits(data:typing.Union[int,float]) -> float:
58
+ return round(data, 5)
59
+ #
60
+
61
+ @staticmethod
62
+ def float_roundTo4FractionDigits(data:typing.Union[int,float]) -> float:
63
+ return round(data, 4)
64
+ #
65
+
66
+ @staticmethod
67
+ def float_roundTo3FractionDigits(data:typing.Union[int,float]) -> float:
68
+ return round(data, 3)
69
+ #
70
+
71
+ @staticmethod
72
+ def float_roundTo2FractionDigits(data:typing.Union[int,float]) -> float:
73
+ return round(data, 2)
74
+ #
75
+
76
+ @staticmethod
77
+ def float_roundTo1FractionDigits(data:typing.Union[int,float]) -> float:
78
+ return round(data, 1)
79
+ #
80
+
81
+ @staticmethod
82
+ def int_toHex(data:int) -> typing.Union[int,str]:
83
+ if data < 0:
84
+ return data
85
+ return _Hex(data)
86
+ #
87
+
88
+ @staticmethod
89
+ def int_toBits(data:int) -> typing.Union[int,str]:
90
+ if data < 0:
91
+ return data
92
+ return _Bits(data)
93
+ #
94
+
95
+ @staticmethod
96
+ def byteChunker(data:bytes, chunkSize:int) -> typing.Generator[bytes,bytes,bytes]:
97
+ assert isinstance(data, bytes)
98
+ assert isinstance(chunkSize, int)
99
+ assert chunkSize > 0
100
+
101
+ iFrom = 0
102
+ iTo = chunkSize
103
+ while iFrom < len(data):
104
+ yield data[iFrom:iTo]
105
+ iFrom = iTo
106
+ iTo += chunkSize
107
+ #
108
+
109
+ #
110
+
111
+
112
+
113
+
114
+
115
+
116
+
@@ -0,0 +1,46 @@
1
+
2
+
3
+
4
+ __author__ = "Jürgen Knauth"
5
+ __version__ = "0.2024.10.20"
6
+ __all__ = (
7
+ "DumperSettings",
8
+ "RawValue",
9
+ "DumpMixin",
10
+ "Dumper",
11
+ "DumpCtx",
12
+ "DEFAULT_DUMPER_SETTINGS",
13
+ "pprint",
14
+ )
15
+
16
+
17
+
18
+
19
+
20
+ from .DumperSettings import DumperSettings
21
+ from .RawValue import RawValue
22
+ from .dumper import DumpMixin, Dumper, DumpCtx, DEFAULT_DUMPER_SETTINGS
23
+
24
+ from builtins import print as _print
25
+
26
+
27
+
28
+
29
+ #
30
+ # Print any value in a human readable way.
31
+ #
32
+ def pprint(something, printFunc = None):
33
+ if printFunc is None:
34
+ printFunc = _print
35
+ else:
36
+ assert callable(printFunc)
37
+
38
+ dumper = Dumper()
39
+ with dumper.createContext(None, "") as dumper2:
40
+ dumper2._dumpX("", something)
41
+ dumper.print(printFunc)
42
+ #
43
+
44
+
45
+
46
+
@@ -7,8 +7,12 @@ import math
7
7
  import codecs
8
8
  #import datetime
9
9
 
10
+ from .RawValue import RawValue
11
+ from .DumperSettings import DumperSettings
10
12
  from ._Hex import _Hex
11
13
  from ._Bits import _Bits
14
+ from ._ConverterFunctions import _ConverterFunctions as _CF
15
+ from ._ByteChunker import _ByteChunker
12
16
 
13
17
 
14
18
 
@@ -17,210 +21,37 @@ from ._Bits import _Bits
17
21
 
18
22
 
19
23
 
20
-
21
-
22
-
23
- class DumperSettings(object):
24
-
25
- def __init__(self):
26
- self.showPrimitivesWithType = False
27
- self.showDictKeysWithType = False
28
- self.showComplexStructsWithType = False
29
- self.compactSequenceLengthLimit = 8
30
- self.compactSequenceItemLengthLimit = 50
31
- self.bytesLineSize = 32
32
- self.compactBytesLinesLengthLimit = 32
33
- #
34
-
35
- #
36
-
37
24
  DEFAULT_DUMPER_SETTINGS = DumperSettings()
38
25
 
39
26
 
40
27
 
41
28
 
42
- def _str_shortenText(text:str) -> str:
43
- if len(text) > 40:
44
- return text[:40] + "..."
45
- else:
46
- return text
47
- #
48
-
49
- def _float_roundTo7FractionDigits(data:typing.Union[int,float]) -> float:
50
- return round(data, 7)
51
- #
52
-
53
- def _float_roundTo6FractionDigits(data:typing.Union[int,float]) -> float:
54
- return round(data, 6)
55
- #
56
-
57
- def _float_roundTo5FractionDigits(data:typing.Union[int,float]) -> float:
58
- return round(data, 5)
59
- #
60
-
61
- def _float_roundTo4FractionDigits(data:typing.Union[int,float]) -> float:
62
- return round(data, 4)
63
- #
64
-
65
- def _float_roundTo3FractionDigits(data:typing.Union[int,float]) -> float:
66
- return round(data, 3)
67
- #
68
-
69
- def _float_roundTo2FractionDigits(data:typing.Union[int,float]) -> float:
70
- return round(data, 2)
71
- #
72
-
73
- def _float_roundTo1FractionDigits(data:typing.Union[int,float]) -> float:
74
- return round(data, 1)
75
- #
76
-
77
- def _int_toHex(data:int) -> typing.Union[int,str]:
78
- if data < 0:
79
- return data
80
- return _Hex(data)
81
- #
82
-
83
- def _int_toBits(data:int) -> typing.Union[int,str]:
84
- if data < 0:
85
- return data
86
- return _Bits(data)
87
- #
88
-
89
- def _byteChunker(data:bytes, chunkSize:int) -> typing.Sequence[bytes]:
90
- assert isinstance(data, bytes)
91
- assert isinstance(chunkSize, int)
92
- assert chunkSize > 0
93
-
94
- iFrom = 0
95
- iTo = chunkSize
96
- while iFrom < len(data):
97
- yield data[iFrom:iTo]
98
- iFrom = iTo
99
- iTo += chunkSize
100
- #
101
-
102
- def _x_byteChunkToHex(data:bytes) -> str:
103
- hexSpanLength = 16 # == 8 bytes for a span
104
-
105
- s = codecs.encode(data, "hex").decode("ascii")
106
- chunks = [ s[i:i+hexSpanLength] for i in range(0, len(s), hexSpanLength) ]
107
- return " ".join(chunks)
108
- #
109
-
110
- def _x_byteChunkToASCII(data:bytes) -> str:
111
- spanLength = 8 # == 8 bytes for a span
112
-
113
- ret = []
114
- for i, b in enumerate(data):
115
- if (i % spanLength) == 0:
116
- ret.append(" ")
117
- if 32 <= b <= 127:
118
- ret.append(chr(b))
119
- else:
120
- ret.append(".")
121
-
122
- return "".join(ret)
123
- #
124
-
125
- #
126
- # Returns chunks of the specified data.
127
- #
128
- def _byteChunkerWithOfs(settings:DumperSettings, data:bytes, processorName:str = None) -> typing.Sequence[typing.Tuple[str,str,str]]:
129
- assert isinstance(settings, DumperSettings)
130
- assert isinstance(data, bytes)
131
- chunkSize = settings.bytesLineSize
132
- assert isinstance(chunkSize, int)
133
- assert chunkSize > 0
134
- hexStrPadded = chunkSize*2 + math.ceil(chunkSize / 8) - 1
135
- if processorName is not None:
136
- assert isinstance(processorName, str)
137
-
138
- # ----
139
-
140
- nTotalLength = len(data)
141
- nTotalLines = math.ceil(nTotalLength / chunkSize)
142
- formatStrFragment = None
143
- formatStrFragmentEllipsis = None
144
- if nTotalLength <= 256*256:
145
- formatStrFragment = "{:04x}"
146
- formatStrFragmentEllipsis = "... "
147
- elif nTotalLength <= 256*256*256:
148
- formatStrFragment = "{:06x}"
149
- formatStrFragmentEllipsis = "... "
150
- else:
151
- formatStrFragment = "{:08x}"
152
- formatStrFragmentEllipsis = "... "
153
-
154
- # ----
155
-
156
- skipFrom = -1
157
- skipTo = -1
158
- if processorName:
159
- if processorName == "shorten":
160
- skipFrom = settings.compactBytesLinesLengthLimit
161
- skipTo = nTotalLines - 4
162
- if skipFrom >= skipTo:
163
- skipFrom = -1
164
- skipTo = -1
165
- else:
166
- raise Exception("No such postprocessor: " + repr(processorName))
167
-
168
- # ----
169
-
170
- if skipFrom < 0:
171
- # direct loop, no addtional if statements
172
- iFrom = 0
173
- iTo = chunkSize
174
- while iFrom < len(data):
175
- chunk = data[iFrom:iTo]
176
- yield formatStrFragment.format(iFrom), _x_byteChunkToHex(chunk).ljust(hexStrPadded), _x_byteChunkToASCII(chunk)
177
- iFrom = iTo
178
- iTo += chunkSize
179
- else:
180
- # loop with if statements
181
- lineNo = 0
182
- iFrom = 0
183
- iTo = chunkSize
184
- while iFrom < len(data):
185
- chunk = data[iFrom:iTo]
186
- if skipFrom <= lineNo <= skipTo:
187
- if skipFrom == lineNo:
188
- yield formatStrFragmentEllipsis, "...".ljust(hexStrPadded), "..."
189
- else:
190
- yield formatStrFragment.format(iFrom), _x_byteChunkToHex(chunk).ljust(hexStrPadded), _x_byteChunkToASCII(chunk)
191
- iFrom = iTo
192
- iTo += chunkSize
193
- lineNo += 1
194
- #
195
-
196
-
197
-
198
29
 
199
30
 
200
31
  _PRIMITIVE_POST_PROCESSORS = {
201
32
  # map associating processor name to tuple consisting of type (or type list) and callable
202
33
 
203
- "shorten": (str, _str_shortenText),
204
- "hex": (int, _int_toHex),
205
- "bit": (int, _int_toBits),
206
- "round1": ((float, int), _float_roundTo1FractionDigits),
207
- "round2": ((float, int), _float_roundTo2FractionDigits),
208
- "round3": ((float, int), _float_roundTo3FractionDigits),
209
- "round4": ((float, int), _float_roundTo4FractionDigits),
210
- "round5": ((float, int), _float_roundTo5FractionDigits),
211
- "round6": ((float, int), _float_roundTo6FractionDigits),
212
- "round7": ((float, int), _float_roundTo7FractionDigits),
213
-
214
- "str_shorten": (str, _str_shortenText),
215
- "float_round7": ((float, int), _float_roundTo7FractionDigits),
216
- "float_round6": ((float, int), _float_roundTo6FractionDigits),
217
- "float_round5": ((float, int), _float_roundTo5FractionDigits),
218
- "float_round4": ((float, int), _float_roundTo4FractionDigits),
219
- "float_round3": ((float, int), _float_roundTo3FractionDigits),
220
- "float_round2": ((float, int), _float_roundTo2FractionDigits),
221
- "float_round1": ((float, int), _float_roundTo1FractionDigits),
222
- "int_hex": (int, _int_toHex),
223
- "int_bit": (int, _int_toBits),
34
+ "shorten": (str, _CF.str_shortenText),
35
+ "hex": (int, _CF.int_toHex),
36
+ "bit": (int, _CF.int_toBits),
37
+ "round1": ((float, int), _CF.float_roundTo1FractionDigits),
38
+ "round2": ((float, int), _CF.float_roundTo2FractionDigits),
39
+ "round3": ((float, int), _CF.float_roundTo3FractionDigits),
40
+ "round4": ((float, int), _CF.float_roundTo4FractionDigits),
41
+ "round5": ((float, int), _CF.float_roundTo5FractionDigits),
42
+ "round6": ((float, int), _CF.float_roundTo6FractionDigits),
43
+ "round7": ((float, int), _CF.float_roundTo7FractionDigits),
44
+
45
+ "str_shorten": (str, _CF.str_shortenText),
46
+ "float_round7": ((float, int), _CF.float_roundTo7FractionDigits),
47
+ "float_round6": ((float, int), _CF.float_roundTo6FractionDigits),
48
+ "float_round5": ((float, int), _CF.float_roundTo5FractionDigits),
49
+ "float_round4": ((float, int), _CF.float_roundTo4FractionDigits),
50
+ "float_round3": ((float, int), _CF.float_roundTo3FractionDigits),
51
+ "float_round2": ((float, int), _CF.float_roundTo2FractionDigits),
52
+ "float_round1": ((float, int), _CF.float_roundTo1FractionDigits),
53
+ "int_hex": (int, _CF.int_toHex),
54
+ "int_bit": (int, _CF.int_toBits),
224
55
  }
225
56
 
226
57
 
@@ -230,24 +61,17 @@ class _Omitted:
230
61
  pass
231
62
  #
232
63
 
233
- class RawValue:
234
-
235
- def __init__(self, text:str) -> None:
236
- assert isinstance(text, str)
237
- self.text = text
238
- #
239
-
240
- #
241
-
242
64
  _OMITTED = _Omitted()
243
65
 
244
66
 
245
67
 
246
68
 
247
69
 
70
+ DumpCtx = typing.NewType("DumpCtx", object)
71
+
248
72
  class DumpCtx(object):
249
73
 
250
- _TYPE_MAP = {} # type -> function
74
+ _TYPE_MAP:typing.Dict[type,typing.Callable[[DumpCtx,str,typing.Any,typing.Union[str,None]],None]] = {} # type -> function
251
75
 
252
76
  def __init__(self, s:DumperSettings, outputLines:list, exitAppend:str, prefix:str):
253
77
  self.__s = s
@@ -313,7 +137,7 @@ class DumpCtx(object):
313
137
  ################################################################################################################################
314
138
 
315
139
  #
316
- # This method outputs a value (recursively).
140
+ # This method outputs a value (recursively). It is the main dump method.
317
141
  # To achieve this this method analyses the data type of the specified value and invokes individual type processing methods if available.
318
142
  #
319
143
  # @param str extraPrefix (required) A prefix to use
@@ -347,7 +171,7 @@ class DumpCtx(object):
347
171
  self._dumpObj(extraPrefix, value, processorName)
348
172
  return
349
173
 
350
- # is it derived from on of our types?
174
+ # is it derived from one of our types?
351
175
 
352
176
  for storedT, m in DumpCtx._TYPE_MAP.items():
353
177
  if isinstance(value, storedT):
@@ -379,7 +203,10 @@ class DumpCtx(object):
379
203
  #
380
204
  def _dumpObj(self, extraPrefix:str, value:object, processorName:str = None):
381
205
  if processorName == "shorten":
382
- self.outputLines.append(self.prefix + extraPrefix + "<" + value.__class__.__name__ + "(...)>")
206
+ if hasattr(value, "_dumpShort"):
207
+ value._dumpShort(ctx2)
208
+ else:
209
+ self.outputLines.append(self.prefix + extraPrefix + "<" + value.__class__.__name__ + "(...)>")
383
210
 
384
211
  else:
385
212
  self.outputLines.append(self.prefix + extraPrefix + "<" + value.__class__.__name__ + "(")
@@ -481,7 +308,7 @@ class DumpCtx(object):
481
308
  else:
482
309
  self.outputLines.append(self.prefix + extraPrefix + e + "<")
483
310
 
484
- for sOfs, chunk, sAscii in _byteChunkerWithOfs(self.__s, value, processorName):
311
+ for sOfs, chunk, sAscii in _ByteChunker.chunkWithOfs(self.__s, value, processorName):
485
312
  self.outputLines.append(self.prefix + "\t" + sOfs + " " + chunk + " " + sAscii)
486
313
 
487
314
  if len(value) == 1:
@@ -762,6 +589,12 @@ or:
762
589
  ]
763
590
  #
764
591
 
592
+ and maybe additionally:
593
+
594
+ def _dumpShort(self, ctx:jk_prettyprintobj.DumpCtx):
595
+ ctx.dumpVar(...)
596
+ #
597
+
765
598
  """
766
599
  ################################################################################################################################
767
600
  ################################################################################################################################
@@ -773,24 +606,32 @@ class DumpMixin:
773
606
 
774
607
  __slots__ = tuple()
775
608
 
776
- def dump(self, prefix:str = None, printFunc = None) -> None:
609
+ def __dump(self, prefix:str = None) -> Dumper:
777
610
  dumper = Dumper()
778
611
  with dumper.createContext(self, prefix) as dumper2:
779
612
  if not dumper2._isDumpableObj(self):
780
613
  raise Exception("Improper object encountered for prettyprinting: " + self.__class__.__name__ + " - Either implement _dump(ctx:DumpCtx) or _dumpVarNames()!")
781
614
  dumper2._dumpObj("", self)
615
+ return dumper
616
+ #
617
+
618
+ def dump(self, prefix:str = None, printFunc = None) -> None:
619
+ dumper = self.__dump(prefix)
782
620
  dumper.print(printFunc)
783
621
  #
784
622
 
785
623
  def dumpToStr(self, prefix:str = None) -> str:
786
- dumper = Dumper()
787
- with dumper.createContext(self, prefix) as dumper2:
788
- if not dumper2._isDumpableObj(self):
789
- raise Exception("Improper object encountered for prettyprinting: " + self.__class__.__name__ + " - Either implement _dump(ctx:DumpCtx) or _dumpVarNames()!")
790
- dumper2._dumpObj("", self)
624
+ dumper = self.__dump(prefix)
791
625
  return dumper.toStr()
792
626
  #
793
627
 
628
+ def dumpToFile(self, filePath:str) -> None:
629
+ dumper = self.__dump()
630
+ assert isinstance(filePath, str)
631
+ with open(filePath, "w", newline="\n", encoding="UTF-8") as fout:
632
+ fout.write(dumper.toStr())
633
+ #
634
+
794
635
  #
795
636
 
796
637
 
@@ -1,16 +0,0 @@
1
-
2
-
3
-
4
- __author__ = "Jürgen Knauth"
5
- __version__ = "0.2024.6.7"
6
-
7
-
8
-
9
- from .dumper import DumpMixin, Dumper, DumpCtx, DEFAULT_DUMPER_SETTINGS, RawValue
10
-
11
-
12
-
13
-
14
-
15
-
16
-