jk_prettyprintobj 0.2024.6.7__tar.gz → 0.2024.10.25__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.25
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.25"
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
+
@@ -1,14 +1,14 @@
1
1
 
2
2
 
3
- import chunk
4
3
  import typing
5
4
  import collections
6
- import math
7
- import codecs
8
- #import datetime
9
5
 
10
- from ._Hex import _Hex
11
- from ._Bits import _Bits
6
+ from .RawValue import RawValue
7
+ from .DumperSettings import DumperSettings
8
+ #from ._Hex import _Hex
9
+ #from ._Bits import _Bits
10
+ from ._ConverterFunctions import _ConverterFunctions as _CF
11
+ from ._ByteChunker import _ByteChunker
12
12
 
13
13
 
14
14
 
@@ -17,210 +17,37 @@ from ._Bits import _Bits
17
17
 
18
18
 
19
19
 
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
20
  DEFAULT_DUMPER_SETTINGS = DumperSettings()
38
21
 
39
22
 
40
23
 
41
24
 
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
25
 
199
26
 
200
27
  _PRIMITIVE_POST_PROCESSORS = {
201
28
  # map associating processor name to tuple consisting of type (or type list) and callable
202
29
 
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),
30
+ "shorten": (str, _CF.str_shortenText),
31
+ "hex": (int, _CF.int_toHex),
32
+ "bit": (int, _CF.int_toBits),
33
+ "round1": ((float, int), _CF.float_roundTo1FractionDigits),
34
+ "round2": ((float, int), _CF.float_roundTo2FractionDigits),
35
+ "round3": ((float, int), _CF.float_roundTo3FractionDigits),
36
+ "round4": ((float, int), _CF.float_roundTo4FractionDigits),
37
+ "round5": ((float, int), _CF.float_roundTo5FractionDigits),
38
+ "round6": ((float, int), _CF.float_roundTo6FractionDigits),
39
+ "round7": ((float, int), _CF.float_roundTo7FractionDigits),
40
+
41
+ "str_shorten": (str, _CF.str_shortenText),
42
+ "float_round7": ((float, int), _CF.float_roundTo7FractionDigits),
43
+ "float_round6": ((float, int), _CF.float_roundTo6FractionDigits),
44
+ "float_round5": ((float, int), _CF.float_roundTo5FractionDigits),
45
+ "float_round4": ((float, int), _CF.float_roundTo4FractionDigits),
46
+ "float_round3": ((float, int), _CF.float_roundTo3FractionDigits),
47
+ "float_round2": ((float, int), _CF.float_roundTo2FractionDigits),
48
+ "float_round1": ((float, int), _CF.float_roundTo1FractionDigits),
49
+ "int_hex": (int, _CF.int_toHex),
50
+ "int_bit": (int, _CF.int_toBits),
224
51
  }
225
52
 
226
53
 
@@ -230,24 +57,17 @@ class _Omitted:
230
57
  pass
231
58
  #
232
59
 
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
60
  _OMITTED = _Omitted()
243
61
 
244
62
 
245
63
 
246
64
 
247
65
 
66
+ DumpCtx = typing.NewType("DumpCtx", object)
67
+
248
68
  class DumpCtx(object):
249
69
 
250
- _TYPE_MAP = {} # type -> function
70
+ _TYPE_MAP:typing.Dict[type,typing.Callable[[DumpCtx,str,typing.Any,typing.Union[str,None]],None]] = {} # type -> function
251
71
 
252
72
  def __init__(self, s:DumperSettings, outputLines:list, exitAppend:str, prefix:str):
253
73
  self.__s = s
@@ -313,7 +133,7 @@ class DumpCtx(object):
313
133
  ################################################################################################################################
314
134
 
315
135
  #
316
- # This method outputs a value (recursively).
136
+ # This method outputs a value (recursively). It is the main dump method.
317
137
  # To achieve this this method analyses the data type of the specified value and invokes individual type processing methods if available.
318
138
  #
319
139
  # @param str extraPrefix (required) A prefix to use
@@ -347,7 +167,7 @@ class DumpCtx(object):
347
167
  self._dumpObj(extraPrefix, value, processorName)
348
168
  return
349
169
 
350
- # is it derived from on of our types?
170
+ # is it derived from one of our types?
351
171
 
352
172
  for storedT, m in DumpCtx._TYPE_MAP.items():
353
173
  if isinstance(value, storedT):
@@ -379,7 +199,10 @@ class DumpCtx(object):
379
199
  #
380
200
  def _dumpObj(self, extraPrefix:str, value:object, processorName:str = None):
381
201
  if processorName == "shorten":
382
- self.outputLines.append(self.prefix + extraPrefix + "<" + value.__class__.__name__ + "(...)>")
202
+ if hasattr(value, "_dumpShort"):
203
+ value._dumpShort(ctx2)
204
+ else:
205
+ self.outputLines.append(self.prefix + extraPrefix + "<" + value.__class__.__name__ + "(...)>")
383
206
 
384
207
  else:
385
208
  self.outputLines.append(self.prefix + extraPrefix + "<" + value.__class__.__name__ + "(")
@@ -481,7 +304,7 @@ class DumpCtx(object):
481
304
  else:
482
305
  self.outputLines.append(self.prefix + extraPrefix + e + "<")
483
306
 
484
- for sOfs, chunk, sAscii in _byteChunkerWithOfs(self.__s, value, processorName):
307
+ for sOfs, chunk, sAscii in _ByteChunker.chunkWithOfs(self.__s, value, processorName):
485
308
  self.outputLines.append(self.prefix + "\t" + sOfs + " " + chunk + " " + sAscii)
486
309
 
487
310
  if len(value) == 1:
@@ -762,6 +585,12 @@ or:
762
585
  ]
763
586
  #
764
587
 
588
+ and maybe additionally:
589
+
590
+ def _dumpShort(self, ctx:jk_prettyprintobj.DumpCtx):
591
+ ctx.dumpVar(...)
592
+ #
593
+
765
594
  """
766
595
  ################################################################################################################################
767
596
  ################################################################################################################################
@@ -773,24 +602,32 @@ class DumpMixin:
773
602
 
774
603
  __slots__ = tuple()
775
604
 
776
- def dump(self, prefix:str = None, printFunc = None) -> None:
605
+ def __dump(self, prefix:str = None) -> Dumper:
777
606
  dumper = Dumper()
778
607
  with dumper.createContext(self, prefix) as dumper2:
779
608
  if not dumper2._isDumpableObj(self):
780
609
  raise Exception("Improper object encountered for prettyprinting: " + self.__class__.__name__ + " - Either implement _dump(ctx:DumpCtx) or _dumpVarNames()!")
781
610
  dumper2._dumpObj("", self)
611
+ return dumper
612
+ #
613
+
614
+ def dump(self, prefix:str = None, printFunc = None) -> None:
615
+ dumper = self.__dump(prefix)
782
616
  dumper.print(printFunc)
783
617
  #
784
618
 
785
619
  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)
620
+ dumper = self.__dump(prefix)
791
621
  return dumper.toStr()
792
622
  #
793
623
 
624
+ def dumpToFile(self, filePath:str) -> None:
625
+ dumper = self.__dump()
626
+ assert isinstance(filePath, str)
627
+ with open(filePath, "w", newline="\n", encoding="UTF-8") as fout:
628
+ fout.write(dumper.toStr())
629
+ #
630
+
794
631
  #
795
632
 
796
633
 
@@ -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
-