transit-python 0.8.321__cp310-abi3-win_amd64.whl
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.
- transit/__init__.py +16 -0
- transit/_accel.py +27 -0
- transit/_native.pyd +0 -0
- transit/class_hash.py +52 -0
- transit/constants.py +23 -0
- transit/decoder.py +185 -0
- transit/helpers.py +41 -0
- transit/read_handlers.py +183 -0
- transit/reader.py +137 -0
- transit/rolling_cache.py +104 -0
- transit/sosjson.py +129 -0
- transit/transit_types.py +267 -0
- transit/write_handlers.py +353 -0
- transit/writer.py +443 -0
- transit_python-0.8.321.dist-info/METADATA +302 -0
- transit_python-0.8.321.dist-info/RECORD +19 -0
- transit_python-0.8.321.dist-info/WHEEL +5 -0
- transit_python-0.8.321.dist-info/licenses/LICENSE +202 -0
- transit_python-0.8.321.dist-info/top_level.txt +1 -0
transit/rolling_cache.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
## Copyright 2014 Cognitect. All Rights Reserved.
|
|
2
|
+
## Copyright 2026 Vendekagon Labs LLC.
|
|
3
|
+
##
|
|
4
|
+
## Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
## you may not use this file except in compliance with the License.
|
|
6
|
+
## You may obtain a copy of the License at
|
|
7
|
+
##
|
|
8
|
+
## http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
##
|
|
10
|
+
## Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
## distributed under the License is distributed on an "AS-IS" BASIS,
|
|
12
|
+
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
## See the License for the specific language governing permissions and
|
|
14
|
+
## limitations under the License.
|
|
15
|
+
|
|
16
|
+
from transit.constants import SUB, MAP_AS_ARR
|
|
17
|
+
|
|
18
|
+
FIRST_ORD = 48
|
|
19
|
+
CACHE_CODE_DIGITS = 44
|
|
20
|
+
CACHE_SIZE = CACHE_CODE_DIGITS * CACHE_CODE_DIGITS
|
|
21
|
+
MIN_SIZE_CACHEABLE = 4
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def is_cache_key(name):
|
|
25
|
+
return len(name) > 0 and name[0] == SUB and name != MAP_AS_ARR
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def encode_key(i):
|
|
29
|
+
lo = i % CACHE_CODE_DIGITS
|
|
30
|
+
hi = i // CACHE_CODE_DIGITS
|
|
31
|
+
if hi == 0:
|
|
32
|
+
return "^" + chr(lo + FIRST_ORD)
|
|
33
|
+
return "^" + chr(hi + FIRST_ORD) + chr(lo + FIRST_ORD)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def decode_key(s):
|
|
37
|
+
sz = len(s)
|
|
38
|
+
if sz == 2:
|
|
39
|
+
return ord(s[1]) - FIRST_ORD
|
|
40
|
+
return (ord(s[2]) - FIRST_ORD) + \
|
|
41
|
+
(CACHE_CODE_DIGITS * (ord(s[1]) - FIRST_ORD))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def is_cacheable(string, as_map_key=False):
|
|
45
|
+
return len(string) >= MIN_SIZE_CACHEABLE \
|
|
46
|
+
and (as_map_key or string[:2] in ("~#", "~$", "~:"))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class RollingCache:
|
|
50
|
+
"""This is the internal cache used by python-transit for cacheing and
|
|
51
|
+
expanding map keys during writing and reading. The cache enables transit
|
|
52
|
+
to minimize the amount of duplicate data sent over the wire, effectively
|
|
53
|
+
compressing down the overall payload size. The cache is not intended to
|
|
54
|
+
be used directly.
|
|
55
|
+
|
|
56
|
+
Readers and writers must agree on cache codes, so this follows the
|
|
57
|
+
transit spec (and transit-java): codes are assigned in order from "^0",
|
|
58
|
+
and once CACHE_SIZE entries are in use the cache starts over from "^0".
|
|
59
|
+
"""
|
|
60
|
+
def __init__(self):
|
|
61
|
+
self.key_to_value = {}
|
|
62
|
+
self.value_to_key = {}
|
|
63
|
+
self.index = 0
|
|
64
|
+
|
|
65
|
+
def decode(self, name, as_map_key=False):
|
|
66
|
+
"""Reading: expand a cache code, or remember a cacheable value.
|
|
67
|
+
Always returns the (uncached) name.
|
|
68
|
+
"""
|
|
69
|
+
if is_cache_key(name):
|
|
70
|
+
try:
|
|
71
|
+
return self.key_to_value[name]
|
|
72
|
+
except KeyError:
|
|
73
|
+
raise ValueError("Unknown cache code: " + name) from None
|
|
74
|
+
if is_cacheable(name, as_map_key):
|
|
75
|
+
self.encache(name)
|
|
76
|
+
return name
|
|
77
|
+
|
|
78
|
+
def encode(self, name, as_map_key=False):
|
|
79
|
+
"""Writing: returns the name the first time and the code after that."""
|
|
80
|
+
if name in self.value_to_key:
|
|
81
|
+
return self.value_to_key[name]
|
|
82
|
+
if is_cacheable(name, as_map_key):
|
|
83
|
+
self.encache(name)
|
|
84
|
+
return name
|
|
85
|
+
|
|
86
|
+
def size(self):
|
|
87
|
+
return len(self.key_to_value)
|
|
88
|
+
|
|
89
|
+
def is_cache_full(self):
|
|
90
|
+
return self.index >= CACHE_SIZE
|
|
91
|
+
|
|
92
|
+
def encache(self, name):
|
|
93
|
+
if self.is_cache_full():
|
|
94
|
+
self.clear()
|
|
95
|
+
key = encode_key(self.index)
|
|
96
|
+
self.index += 1
|
|
97
|
+
self.key_to_value[key] = name
|
|
98
|
+
self.value_to_key[name] = key
|
|
99
|
+
return name
|
|
100
|
+
|
|
101
|
+
def clear(self):
|
|
102
|
+
self.key_to_value = {}
|
|
103
|
+
self.value_to_key = {}
|
|
104
|
+
self.index = 0
|
transit/sosjson.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
## copyright 2014 cognitect. all rights reserved.
|
|
2
|
+
## Copyright 2026 Vendekagon Labs LLC.
|
|
3
|
+
##
|
|
4
|
+
## licensed under the apache license, version 2.0 (the "license");
|
|
5
|
+
## you may not use this file except in compliance with the license.
|
|
6
|
+
## you may obtain a copy of the license at
|
|
7
|
+
##
|
|
8
|
+
## http://www.apache.org/licenses/license-2.0
|
|
9
|
+
##
|
|
10
|
+
## unless required by applicable law or agreed to in writing, software
|
|
11
|
+
## distributed under the license is distributed on an "as-is" basis,
|
|
12
|
+
## without warranties or conditions of any kind, either express or implied.
|
|
13
|
+
## see the license for the specific language governing permissions and
|
|
14
|
+
## limitations under the license.
|
|
15
|
+
# Streaming reads of a sequence of JSON texts (as sent over a pipe or socket),
|
|
16
|
+
# yielding each top level value as soon as it has fully arrived.
|
|
17
|
+
#
|
|
18
|
+
# Rather than scanning a character at a time, whatever data is available is
|
|
19
|
+
# read in one go and a regex skips ahead to the characters that matter for
|
|
20
|
+
# finding the end of a value (brackets, quotes and escapes). Each complete
|
|
21
|
+
# value is then handed to json.loads.
|
|
22
|
+
import codecs
|
|
23
|
+
import json
|
|
24
|
+
import re
|
|
25
|
+
|
|
26
|
+
CHUNK_SIZE = 64 * 1024
|
|
27
|
+
|
|
28
|
+
_NON_WS = re.compile(r"[^ \t\n\r]")
|
|
29
|
+
_STRUCTURAL = re.compile(r'[\[\]{}"]')
|
|
30
|
+
_IN_STRING = re.compile(r'["\\]')
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def read_available(stream, size=CHUNK_SIZE):
|
|
34
|
+
"""Return a function that reads whatever data is available from stream,
|
|
35
|
+
blocking only until there is some. Returns an empty value at EOF.
|
|
36
|
+
"""
|
|
37
|
+
buffer = getattr(stream, "buffer", None)
|
|
38
|
+
if buffer is not None and hasattr(buffer, "read1"):
|
|
39
|
+
# A text wrapper (e.g. sys.stdin); read(n) on it blocks until n
|
|
40
|
+
# characters arrive, so read bytes from the underlying buffer.
|
|
41
|
+
return lambda: buffer.read1(size)
|
|
42
|
+
if hasattr(stream, "read1"):
|
|
43
|
+
return lambda: stream.read1(size)
|
|
44
|
+
return lambda: stream.read(size)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def chunks_raw(stream):
|
|
48
|
+
"""Yield data from stream as it becomes available, until EOF."""
|
|
49
|
+
read = read_available(stream)
|
|
50
|
+
while True:
|
|
51
|
+
data = read()
|
|
52
|
+
if not data:
|
|
53
|
+
return
|
|
54
|
+
yield data
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def chunks(stream):
|
|
58
|
+
"""Yield text from stream as it becomes available, decoding bytes as UTF-8."""
|
|
59
|
+
decoder = codecs.getincrementaldecoder("utf-8")()
|
|
60
|
+
for data in chunks_raw(stream):
|
|
61
|
+
text = data if isinstance(data, str) else decoder.decode(data)
|
|
62
|
+
if text:
|
|
63
|
+
yield text
|
|
64
|
+
decoder.decode(b"", final=True) # raises on truncated UTF-8
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def yield_json(stream):
|
|
68
|
+
"""Yield the text of each top level JSON array, object or string in stream."""
|
|
69
|
+
buf = ""
|
|
70
|
+
pos = 0 # where to resume scanning in buf
|
|
71
|
+
start = None # start of the value being read, None between values
|
|
72
|
+
depth = 0
|
|
73
|
+
in_string = False
|
|
74
|
+
for text in chunks(stream):
|
|
75
|
+
buf += text
|
|
76
|
+
while True:
|
|
77
|
+
if start is None:
|
|
78
|
+
m = _NON_WS.search(buf, pos)
|
|
79
|
+
if not m:
|
|
80
|
+
buf, pos = "", 0
|
|
81
|
+
break
|
|
82
|
+
start = m.start()
|
|
83
|
+
c = buf[start]
|
|
84
|
+
pos = start + 1
|
|
85
|
+
if c == '"':
|
|
86
|
+
in_string = True
|
|
87
|
+
elif c in "[{":
|
|
88
|
+
depth = 1
|
|
89
|
+
else:
|
|
90
|
+
raise ValueError("Expected a JSON array, object or string, "
|
|
91
|
+
"found: " + repr(buf[start:start + 20]))
|
|
92
|
+
elif in_string:
|
|
93
|
+
m = _IN_STRING.search(buf, pos)
|
|
94
|
+
if not m:
|
|
95
|
+
pos = len(buf)
|
|
96
|
+
break
|
|
97
|
+
if m.group() == "\\":
|
|
98
|
+
if m.end() == len(buf):
|
|
99
|
+
# escaped character hasn't arrived yet
|
|
100
|
+
pos = m.start()
|
|
101
|
+
break
|
|
102
|
+
pos = m.end() + 1
|
|
103
|
+
continue
|
|
104
|
+
pos = m.end()
|
|
105
|
+
in_string = False
|
|
106
|
+
else:
|
|
107
|
+
m = _STRUCTURAL.search(buf, pos)
|
|
108
|
+
if not m:
|
|
109
|
+
pos = len(buf)
|
|
110
|
+
break
|
|
111
|
+
c = m.group()
|
|
112
|
+
pos = m.end()
|
|
113
|
+
if c == '"':
|
|
114
|
+
in_string = True
|
|
115
|
+
continue
|
|
116
|
+
depth += 1 if c in "[{" else -1
|
|
117
|
+
if depth == 0 and not in_string:
|
|
118
|
+
yield buf[start:pos]
|
|
119
|
+
buf, pos, start = buf[pos:], 0, None
|
|
120
|
+
if start is not None:
|
|
121
|
+
raise ValueError("Stream ended in the middle of a JSON value")
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def items(stream, **kwargs):
|
|
125
|
+
"""Yield each top level JSON value in stream as soon as it is available.
|
|
126
|
+
Keyword arguments are passed to json.loads (e.g. object_pairs_hook).
|
|
127
|
+
"""
|
|
128
|
+
for s in yield_json(stream):
|
|
129
|
+
yield json.loads(s, **kwargs)
|
transit/transit_types.py
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
## Copyright 2014 Cognitect. All Rights Reserved.
|
|
2
|
+
## Copyright 2026 Vendekagon Labs LLC.
|
|
3
|
+
##
|
|
4
|
+
## Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
## you may not use this file except in compliance with the License.
|
|
6
|
+
## You may obtain a copy of the License at
|
|
7
|
+
##
|
|
8
|
+
## http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
##
|
|
10
|
+
## Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
## distributed under the License is distributed on an "AS-IS" BASIS,
|
|
12
|
+
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
## See the License for the specific language governing permissions and
|
|
14
|
+
## limitations under the License.
|
|
15
|
+
from collections.abc import Hashable, Mapping
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Named:
|
|
19
|
+
def _parse(self):
|
|
20
|
+
p = self.str.split('/', 1)
|
|
21
|
+
if len(p) == 1:
|
|
22
|
+
self._name = self.str
|
|
23
|
+
self._namespace = None
|
|
24
|
+
else:
|
|
25
|
+
self._namespace = p[0] or None
|
|
26
|
+
self._name = p[1] or "/"
|
|
27
|
+
return self._name, self._namespace
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def name(self):
|
|
31
|
+
return self._name if hasattr(self, "_name") else self._parse()[0]
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def namespace(self):
|
|
35
|
+
return self._namespace if hasattr(self, "_namespace") \
|
|
36
|
+
else self._parse()[1]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class Keyword(Named):
|
|
40
|
+
def __init__(self, value):
|
|
41
|
+
assert isinstance(value, str)
|
|
42
|
+
self.str = value
|
|
43
|
+
self.hv = value.__hash__()
|
|
44
|
+
|
|
45
|
+
def __hash__(self):
|
|
46
|
+
return self.hv
|
|
47
|
+
|
|
48
|
+
def __eq__(self, other):
|
|
49
|
+
return isinstance(other, Keyword) and self.str == other.str
|
|
50
|
+
|
|
51
|
+
def __ne__(self, other):
|
|
52
|
+
return not self == other
|
|
53
|
+
|
|
54
|
+
def __call__(self, mp):
|
|
55
|
+
return mp[self]
|
|
56
|
+
|
|
57
|
+
def __repr__(self):
|
|
58
|
+
return "<Keyword " + self.str + ">"
|
|
59
|
+
|
|
60
|
+
def __str__(self):
|
|
61
|
+
return self.str
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Symbol(Named):
|
|
65
|
+
def __init__(self, value):
|
|
66
|
+
assert isinstance(value, str)
|
|
67
|
+
self.str = value
|
|
68
|
+
self.hv = value.__hash__()
|
|
69
|
+
|
|
70
|
+
def __hash__(self):
|
|
71
|
+
return self.hv
|
|
72
|
+
|
|
73
|
+
def __eq__(self, other):
|
|
74
|
+
return isinstance(other, Symbol) and self.str == other.str
|
|
75
|
+
|
|
76
|
+
def __ne__(self, other):
|
|
77
|
+
return not self == other
|
|
78
|
+
|
|
79
|
+
def __call__(self, mp):
|
|
80
|
+
return mp[self]
|
|
81
|
+
|
|
82
|
+
def __repr__(self):
|
|
83
|
+
return self.str
|
|
84
|
+
|
|
85
|
+
def __str__(self):
|
|
86
|
+
return self.str
|
|
87
|
+
|
|
88
|
+
kw_cache = {}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class _KWS:
|
|
92
|
+
def __getattr__(self, item):
|
|
93
|
+
value = self(item)
|
|
94
|
+
setattr(self, item, value)
|
|
95
|
+
return value
|
|
96
|
+
|
|
97
|
+
def __call__(self, str):
|
|
98
|
+
if str in kw_cache:
|
|
99
|
+
return kw_cache[str]
|
|
100
|
+
else:
|
|
101
|
+
kw_cache[str] = Keyword(str)
|
|
102
|
+
return kw_cache[str]
|
|
103
|
+
|
|
104
|
+
kws = _KWS()
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class TaggedValue:
|
|
108
|
+
def __init__(self, tag, rep):
|
|
109
|
+
self.tag = tag
|
|
110
|
+
self.rep = rep
|
|
111
|
+
|
|
112
|
+
def __eq__(self, other):
|
|
113
|
+
if isinstance(other, TaggedValue):
|
|
114
|
+
return self.tag == other.tag and \
|
|
115
|
+
self.rep == other.rep
|
|
116
|
+
return False
|
|
117
|
+
|
|
118
|
+
def __ne__(self, other):
|
|
119
|
+
return not (self == other)
|
|
120
|
+
|
|
121
|
+
def __hash__(self):
|
|
122
|
+
if isinstance(self.rep, list):
|
|
123
|
+
return hash(tuple(self.rep))
|
|
124
|
+
return hash(self.rep)
|
|
125
|
+
|
|
126
|
+
def __str__(self):
|
|
127
|
+
return repr(self)
|
|
128
|
+
|
|
129
|
+
def __repr__(self):
|
|
130
|
+
return self.tag + " " + repr(self.rep)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class Set(TaggedValue):
|
|
134
|
+
def __init__(self, rep):
|
|
135
|
+
TaggedValue.__init__(self, "set", rep)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class CMap(TaggedValue):
|
|
139
|
+
def __init__(self, rep):
|
|
140
|
+
TaggedValue.__init__(self, "cmap", rep)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class Vector(TaggedValue):
|
|
144
|
+
def __init__(self, rep):
|
|
145
|
+
TaggedValue.__init__(self, "vector", rep)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class Array(TaggedValue):
|
|
149
|
+
def __init__(self, rep):
|
|
150
|
+
TaggedValue.__init__(self, "array", rep)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class List(TaggedValue):
|
|
154
|
+
def __init__(self, rep):
|
|
155
|
+
TaggedValue.__init__(self, "list", rep)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class URI(TaggedValue):
|
|
159
|
+
def __init__(self, rep):
|
|
160
|
+
TaggedValue.__init__(self, "uri", rep)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class frozendict(Mapping, Hashable):
|
|
164
|
+
def __init__(self, *args, **kwargs):
|
|
165
|
+
self._dict = dict(*args, **kwargs)
|
|
166
|
+
|
|
167
|
+
def __len__(self):
|
|
168
|
+
return len(self._dict)
|
|
169
|
+
|
|
170
|
+
def __iter__(self):
|
|
171
|
+
return iter(self._dict)
|
|
172
|
+
|
|
173
|
+
def __getitem__(self, key):
|
|
174
|
+
return self._dict[key]
|
|
175
|
+
|
|
176
|
+
def __hash__(self):
|
|
177
|
+
return hash(frozenset(self._dict.items()))
|
|
178
|
+
|
|
179
|
+
def __repr__(self):
|
|
180
|
+
return 'frozendict(%r)' % (self._dict,)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class Link:
|
|
184
|
+
# Class property constants for rendering types
|
|
185
|
+
LINK = "link"
|
|
186
|
+
IMAGE = "image"
|
|
187
|
+
|
|
188
|
+
# Class property constants for keywords/obj properties.
|
|
189
|
+
HREF = "href"
|
|
190
|
+
REL = "rel"
|
|
191
|
+
PROMPT = "prompt"
|
|
192
|
+
NAME = "name"
|
|
193
|
+
RENDER = "render"
|
|
194
|
+
|
|
195
|
+
def __init__(self, href=None, rel=None, name=None, render=None,
|
|
196
|
+
prompt=None):
|
|
197
|
+
self._dict = frozendict()
|
|
198
|
+
assert href and rel
|
|
199
|
+
if render:
|
|
200
|
+
assert render.lower() in [Link.LINK, Link.IMAGE]
|
|
201
|
+
self._dict = {Link.HREF: href,
|
|
202
|
+
Link.REL: rel,
|
|
203
|
+
Link.NAME: name,
|
|
204
|
+
Link.RENDER: render,
|
|
205
|
+
Link.PROMPT: prompt}
|
|
206
|
+
|
|
207
|
+
def __eq__(self, other):
|
|
208
|
+
return self._dict == other._dict
|
|
209
|
+
|
|
210
|
+
def __ne__(self, other):
|
|
211
|
+
return self._dict != other._dict
|
|
212
|
+
|
|
213
|
+
@property
|
|
214
|
+
def href(self):
|
|
215
|
+
return self._dict[Link.HREF]
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def rel(self):
|
|
219
|
+
return self._dict[Link.REL]
|
|
220
|
+
|
|
221
|
+
@property
|
|
222
|
+
def prompt(self):
|
|
223
|
+
return self._dict[Link.PROMPT]
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def name(self):
|
|
227
|
+
return self._dict[Link.NAME]
|
|
228
|
+
|
|
229
|
+
@property
|
|
230
|
+
def render(self):
|
|
231
|
+
return self._dict[Link.RENDER]
|
|
232
|
+
|
|
233
|
+
@property
|
|
234
|
+
def as_map(self):
|
|
235
|
+
return self._dict
|
|
236
|
+
|
|
237
|
+
@property
|
|
238
|
+
def as_array(self):
|
|
239
|
+
return [self.href, self.rel, self.name, self.render, self.prompt]
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class Boolean:
|
|
243
|
+
"""To allow a separate t/f that won't hash as 1/0. Don't call directly,
|
|
244
|
+
instead use true and false as singleton objects. Can use with type check.
|
|
245
|
+
|
|
246
|
+
Note that the Booleans are for preserving hash/set bools that duplicate 1/0
|
|
247
|
+
and not designed for use in Python outside logical evaluation (don't treat
|
|
248
|
+
as an int, they're not). You can get a Python bool using bool(x)
|
|
249
|
+
where x is a true or false Boolean.
|
|
250
|
+
"""
|
|
251
|
+
def __init__(self, name):
|
|
252
|
+
self.v = True if name == "true" else False
|
|
253
|
+
self.name = name
|
|
254
|
+
|
|
255
|
+
def __bool__(self):
|
|
256
|
+
return self.v
|
|
257
|
+
|
|
258
|
+
def __repr__(self):
|
|
259
|
+
return self.name
|
|
260
|
+
|
|
261
|
+
def __str__(self):
|
|
262
|
+
return self.name
|
|
263
|
+
|
|
264
|
+
# lowercase rep matches java/clojure
|
|
265
|
+
|
|
266
|
+
false = Boolean("false")
|
|
267
|
+
true = Boolean("true")
|