File: writer.py

package info (click to toggle)
pycson 0.8-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 284 kB
  • sloc: python: 546; makefile: 3
file content (191 lines) | stat: -rw-r--r-- 6,879 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
import re, json, sys

if sys.version_info[0] == 2:
    def _is_num(o):
        return isinstance(o, int) or isinstance(o, long) or isinstance(o, float)
    def _stringify(o):
        if isinstance(o, str):
            return unicode(o)
        if isinstance(o, unicode):
            return o
        return None
else:
    def _is_num(o):
        return isinstance(o, int) or isinstance(o, float)
    def _stringify(o):
        if isinstance(o, bytes):
            return o.decode()
        if isinstance(o, str):
            return o
        return None

_id_re = re.compile(r'[$a-zA-Z_][$0-9a-zA-Z_]*\Z')

class CSONEncoder:
    def __init__(self, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False,
            indent=None, default=None):
        self._skipkeys = skipkeys
        self._ensure_ascii = ensure_ascii
        self._allow_nan = allow_nan
        self._sort_keys = sort_keys
        self._indent = ' ' * (indent or 4)
        self._default = default
        if check_circular:
            self._obj_stack = set()
        else:
            self._obj_stack = None

    def _format_simple_val(self, o):
        if o is None:
            return 'null'
        if isinstance(o, bool):
            return 'true' if o else 'false'
        if _is_num(o):
            return str(o)
        s = _stringify(o)
        if s is not None:
            return self._escape_string(s)
        return None

    def _escape_string(self, s):
        r = json.dumps(s, ensure_ascii=self._ensure_ascii)
        return u"'{}'".format(r[1:-1].replace("'", r"\'"))

    def _escape_key(self, s):
        if s is None or isinstance(s, bool) or _is_num(s):
            s = str(s)
        s = _stringify(s)
        if s is None:
            if self._skipkeys:
                return None
            raise TypeError('keys must be a string')
        if not _id_re.match(s):
            return self._escape_string(s)
        return s

    def _push_obj(self, o):
        if self._obj_stack is not None:
            if id(o) in self._obj_stack:
                raise ValueError('Circular reference detected')
            self._obj_stack.add(id(o))

    def _pop_obj(self, o):
        if self._obj_stack is not None:
            self._obj_stack.remove(id(o))

    def _encode(self, o, obj_val=False, indent='', force_flow=False):
        if isinstance(o, list):
            if not o:
                if obj_val:
                    yield ' []\n'
                else:
                    yield indent
                    yield '[]\n'
            else:
                if obj_val:
                    yield ' [\n'
                else:
                    yield indent
                    yield '[\n'
                    indent = indent + self._indent
                self._push_obj(o)
                for v in o:
                    for chunk in self._encode(v, obj_val=False, indent=indent, force_flow=True):
                        yield chunk
                self._pop_obj(o)
                yield indent[:-len(self._indent)]
                yield ']\n'
        elif isinstance(o, dict):
            items = [(self._escape_key(k), v) for k, v in o.items()]
            if self._skipkeys:
                items = [(k, v) for k, v in items if k is not None]
            if self._sort_keys:
                items.sort()
            if force_flow or not items:
                if not items:
                    if obj_val:
                        yield ' {}\n'
                    else:
                        yield indent
                        yield '{}\n'
                else:
                    if obj_val:
                        yield ' {\n'
                    else:
                        yield indent
                        yield '{\n'
                        indent = indent + self._indent
                    self._push_obj(o)
                    for k, v in items:
                        yield indent
                        yield k
                        yield ':'
                        for chunk in self._encode(v, obj_val=True, indent=indent + self._indent, force_flow=False):
                            yield chunk
                    self._pop_obj(o)
                    yield indent[:-len(self._indent)]
                    yield '}\n'
            else:
                if obj_val:
                    yield '\n'
                self._push_obj(o)
                for k, v in items:
                    yield indent
                    yield k
                    yield ':'
                    for chunk in self._encode(v, obj_val=True, indent=indent + self._indent, force_flow=False):
                        yield chunk
                self._pop_obj(o)
        else:
            v = self._format_simple_val(o)
            if v is None:
                self._push_obj(o)
                v = self.default(o)
                for chunk in self._encode(v, obj_val=obj_val, indent=indent, force_flow=force_flow):
                    yield chunk
                self._pop_obj(o)
            else:
                if obj_val:
                    yield ' '
                else:
                    yield indent
                yield v
                yield '\n'

    def iterencode(self, o):
        return self._encode(o)

    def encode(self, o):
        return ''.join(self.iterencode(o))

    def default(self, o):
        if self._default is None:
            raise TypeError('Cannot serialize an object of type {}'.format(type(o).__name__))
        return self._default(o)

def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None,
        indent=None, default=None, sort_keys=False, **kw):
    if indent is None and cls is None:
        return json.dump(obj, fp, skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular,
            allow_nan=allow_nan, default=default, sort_keys=sort_keys, separators=(',', ':'))

    if cls is None:
        cls = CSONEncoder
    encoder = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular,
        allow_nan=allow_nan, sort_keys=sort_keys, indent=indent, default=default, **kw)

    for chunk in encoder.iterencode(obj):
        fp.write(chunk)

def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None,
        default=None, sort_keys=False, **kw):
    if indent is None and cls is None:
        return json.dumps(obj, skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular,
            allow_nan=allow_nan, default=default, sort_keys=sort_keys, separators=(',', ':'))

    if cls is None:
        cls = CSONEncoder
    encoder = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular,
        allow_nan=allow_nan, sort_keys=sort_keys, indent=indent, default=default, **kw)

    return encoder.encode(obj)