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.
- {jk_prettyprintobj-0.2024.6.7 → jk_prettyprintobj-0.2024.10.20}/PKG-INFO +1 -1
- jk_prettyprintobj-0.2024.10.20/jk_prettyprintobj/DumperSettings.py +51 -0
- jk_prettyprintobj-0.2024.10.20/jk_prettyprintobj/RawValue.py +47 -0
- jk_prettyprintobj-0.2024.10.20/jk_prettyprintobj/_ByteChunker.py +152 -0
- jk_prettyprintobj-0.2024.10.20/jk_prettyprintobj/_ConverterFunctions.py +116 -0
- jk_prettyprintobj-0.2024.10.20/jk_prettyprintobj/__init__.py +46 -0
- {jk_prettyprintobj-0.2024.6.7 → jk_prettyprintobj-0.2024.10.20}/jk_prettyprintobj/dumper.py +55 -214
- jk_prettyprintobj-0.2024.6.7/jk_prettyprintobj/__init__.py +0 -16
- {jk_prettyprintobj-0.2024.6.7 → jk_prettyprintobj-0.2024.10.20}/README.md +0 -0
- {jk_prettyprintobj-0.2024.6.7 → jk_prettyprintobj-0.2024.10.20}/jk_prettyprintobj/_Bits.py +0 -0
- {jk_prettyprintobj-0.2024.6.7 → jk_prettyprintobj-0.2024.10.20}/jk_prettyprintobj/_Hex.py +0 -0
- {jk_prettyprintobj-0.2024.6.7 → jk_prettyprintobj-0.2024.10.20}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: jk_prettyprintobj
|
3
|
-
Version: 0.2024.
|
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,
|
204
|
-
"hex": (int,
|
205
|
-
"bit": (int,
|
206
|
-
"round1": ((float, int),
|
207
|
-
"round2": ((float, int),
|
208
|
-
"round3": ((float, int),
|
209
|
-
"round4": ((float, int),
|
210
|
-
"round5": ((float, int),
|
211
|
-
"round6": ((float, int),
|
212
|
-
"round7": ((float, int),
|
213
|
-
|
214
|
-
"str_shorten": (str,
|
215
|
-
"float_round7": ((float, int),
|
216
|
-
"float_round6": ((float, int),
|
217
|
-
"float_round5": ((float, int),
|
218
|
-
"float_round4": ((float, int),
|
219
|
-
"float_round3": ((float, int),
|
220
|
-
"float_round2": ((float, int),
|
221
|
-
"float_round1": ((float, int),
|
222
|
-
"int_hex": (int,
|
223
|
-
"int_bit": (int,
|
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
|
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
|
-
|
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
|
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
|
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 =
|
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
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|