rapydscript-ns 0.9.0 → 0.9.1
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.
- package/CHANGELOG.md +8 -0
- package/README.md +6 -5
- package/TODO.md +1 -3
- package/language-service/index.js +4 -4
- package/package.json +1 -1
- package/release/compiler.js +2 -2
- package/release/signatures.json +3 -3
- package/src/lib/contextlib.pyj +379 -0
- package/src/lib/datetime.pyj +712 -0
- package/src/lib/io.pyj +500 -0
- package/src/lib/json.pyj +227 -0
- package/src/monaco-language-service/diagnostics.js +2 -2
- package/src/tokenizer.pyj +1 -1
- package/test/contextlib.pyj +362 -0
- package/test/datetime.pyj +500 -0
- package/test/debugger_stmt.pyj +41 -0
- package/test/io.pyj +316 -0
- package/test/json.pyj +196 -0
- package/test/unit/web-repl.js +533 -0
- package/web-repl/rapydscript.js +2 -2
package/src/lib/io.pyj
ADDED
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
###########################################################
|
|
2
|
+
# RapydScript Standard Library
|
|
3
|
+
# Author: RapydScript-NS Contributors
|
|
4
|
+
# Copyright 2024 RapydScript-NS Contributors
|
|
5
|
+
# License: Apache License 2.0
|
|
6
|
+
###########################################################
|
|
7
|
+
|
|
8
|
+
# Python-compatible io module.
|
|
9
|
+
#
|
|
10
|
+
# Provides StringIO and BytesIO — in-memory file-like objects that implement
|
|
11
|
+
# the same read/write/seek interface as Python's io.StringIO and io.BytesIO.
|
|
12
|
+
#
|
|
13
|
+
# Usage:
|
|
14
|
+
# from io import StringIO, BytesIO, UnsupportedOperation
|
|
15
|
+
#
|
|
16
|
+
# sio = StringIO('hello')
|
|
17
|
+
# sio.seek(0)
|
|
18
|
+
# print(sio.read()) # 'hello'
|
|
19
|
+
#
|
|
20
|
+
# bio = BytesIO(bytes([72, 105]))
|
|
21
|
+
# bio.seek(0)
|
|
22
|
+
# print(bio.read()) # bytes([72, 105])
|
|
23
|
+
#
|
|
24
|
+
# Implementation notes:
|
|
25
|
+
# - StringIO is backed by a plain JS string with an integer position cursor.
|
|
26
|
+
# - BytesIO is backed by a plain JS array of integers (0-255), with read()
|
|
27
|
+
# returning a bytes() object.
|
|
28
|
+
# - write() at a position in the middle of the buffer overwrites bytes in
|
|
29
|
+
# place (matching Python semantics); write() past the end zero-pads.
|
|
30
|
+
# - The `closed` attribute is a plain instance variable (not a property),
|
|
31
|
+
# since RapydScript does not support @property descriptors.
|
|
32
|
+
# - `newline` parameter to StringIO is accepted for API compatibility but
|
|
33
|
+
# not processed (universal newline translation is not performed).
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
# Internal JS helper
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
v"""
|
|
41
|
+
// Convert a bytes-like value to a plain JS array of integers.
|
|
42
|
+
// Handles: ρσ_bytes / ρσ_bytearray (._data), Uint8Array, Int8Array,
|
|
43
|
+
// plain JS Array, and strings (latin-1 codepoints).
|
|
44
|
+
function _io_bytes_to_array(b) {
|
|
45
|
+
if (b === null || b === undefined) return [];
|
|
46
|
+
// RapydScript bytes / bytearray carry their data in ._data
|
|
47
|
+
if (b._data !== undefined && b._data !== null) {
|
|
48
|
+
return b._data.slice();
|
|
49
|
+
}
|
|
50
|
+
if (b instanceof Uint8Array || b instanceof Int8Array) {
|
|
51
|
+
var r = [];
|
|
52
|
+
for (var i = 0; i < b.length; i++) r.push(b[i] & 0xFF);
|
|
53
|
+
return r;
|
|
54
|
+
}
|
|
55
|
+
if (Array.isArray(b)) {
|
|
56
|
+
return b.slice();
|
|
57
|
+
}
|
|
58
|
+
if (typeof b === 'string') {
|
|
59
|
+
var r2 = [];
|
|
60
|
+
for (var j = 0; j < b.length; j++) r2.push(b.charCodeAt(j) & 0xFF);
|
|
61
|
+
return r2;
|
|
62
|
+
}
|
|
63
|
+
// fallback: try length-indexed access
|
|
64
|
+
var r3 = [];
|
|
65
|
+
for (var k = 0; k < (b.length || 0); k++) r3.push((b[k] | 0) & 0xFF);
|
|
66
|
+
return r3;
|
|
67
|
+
}
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# ---------------------------------------------------------------------------
|
|
72
|
+
# Exceptions
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
class UnsupportedOperation(Exception):
|
|
76
|
+
"""Raised when an unsupported IO operation is attempted."""
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# ---------------------------------------------------------------------------
|
|
81
|
+
# Base class
|
|
82
|
+
# ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
class IOBase:
|
|
85
|
+
"""Minimal base class shared by StringIO and BytesIO."""
|
|
86
|
+
|
|
87
|
+
def __init__(self):
|
|
88
|
+
self.closed = False
|
|
89
|
+
|
|
90
|
+
def _check_closed(self):
|
|
91
|
+
if self.closed:
|
|
92
|
+
raise ValueError('I/O operation on closed file.')
|
|
93
|
+
|
|
94
|
+
def close(self):
|
|
95
|
+
"""Mark the stream as closed."""
|
|
96
|
+
self.closed = True
|
|
97
|
+
|
|
98
|
+
def readable(self):
|
|
99
|
+
"""Return True — StringIO/BytesIO are always readable."""
|
|
100
|
+
return True
|
|
101
|
+
|
|
102
|
+
def writable(self):
|
|
103
|
+
"""Return True — StringIO/BytesIO are always writable."""
|
|
104
|
+
return True
|
|
105
|
+
|
|
106
|
+
def seekable(self):
|
|
107
|
+
"""Return True — StringIO/BytesIO are always seekable."""
|
|
108
|
+
return True
|
|
109
|
+
|
|
110
|
+
def __enter__(self):
|
|
111
|
+
self._check_closed()
|
|
112
|
+
return self
|
|
113
|
+
|
|
114
|
+
def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
|
|
115
|
+
self.close()
|
|
116
|
+
return False
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# ---------------------------------------------------------------------------
|
|
120
|
+
# StringIO
|
|
121
|
+
# ---------------------------------------------------------------------------
|
|
122
|
+
|
|
123
|
+
class StringIO(IOBase):
|
|
124
|
+
"""
|
|
125
|
+
In-memory text stream backed by a string.
|
|
126
|
+
|
|
127
|
+
Mirrors the interface of Python's io.StringIO:
|
|
128
|
+
read([size]) — read up to *size* characters (-1 or None = all)
|
|
129
|
+
readline([size]) — read one line (up to *size* chars)
|
|
130
|
+
readlines([hint]) — read all lines; stop early when total ≥ hint
|
|
131
|
+
write(s) — write string *s* at the current position
|
|
132
|
+
writelines(lines) — write each item in *lines*
|
|
133
|
+
getvalue() — return the full buffer contents
|
|
134
|
+
seek(pos[, whence]) — reposition (0=absolute, 1=relative, 2=from end)
|
|
135
|
+
tell() — return the current position
|
|
136
|
+
truncate([pos]) — truncate buffer at *pos* (default: current pos)
|
|
137
|
+
close() — mark the stream as closed
|
|
138
|
+
closed — True after close()
|
|
139
|
+
|
|
140
|
+
Example::
|
|
141
|
+
|
|
142
|
+
sio = StringIO()
|
|
143
|
+
sio.write('hello ')
|
|
144
|
+
sio.write('world')
|
|
145
|
+
sio.seek(0)
|
|
146
|
+
print(sio.read()) # 'hello world'
|
|
147
|
+
|
|
148
|
+
The stream also works as a context manager::
|
|
149
|
+
|
|
150
|
+
with StringIO('data') as f:
|
|
151
|
+
text = f.read()
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
def __init__(self, initial_value='', newline='\n'):
|
|
155
|
+
IOBase.__init__(self)
|
|
156
|
+
self._buf = str(initial_value) if initial_value is not None else ''
|
|
157
|
+
self._pos = 0
|
|
158
|
+
|
|
159
|
+
def getvalue(self):
|
|
160
|
+
"""Return the entire contents of the buffer as a string."""
|
|
161
|
+
self._check_closed()
|
|
162
|
+
return self._buf
|
|
163
|
+
|
|
164
|
+
def read(self, size=-1):
|
|
165
|
+
"""
|
|
166
|
+
Read up to *size* characters from the current position.
|
|
167
|
+
|
|
168
|
+
If *size* is -1 or None, read until end of stream.
|
|
169
|
+
Returns the data as a string.
|
|
170
|
+
"""
|
|
171
|
+
self._check_closed()
|
|
172
|
+
buflen = len(self._buf)
|
|
173
|
+
if self._pos >= buflen:
|
|
174
|
+
return ''
|
|
175
|
+
if size is None or size < 0:
|
|
176
|
+
result = self._buf[self._pos:]
|
|
177
|
+
self._pos = buflen
|
|
178
|
+
else:
|
|
179
|
+
end = min(self._pos + size, buflen)
|
|
180
|
+
result = self._buf[self._pos:end]
|
|
181
|
+
self._pos = end
|
|
182
|
+
return result
|
|
183
|
+
|
|
184
|
+
def readline(self, size=-1):
|
|
185
|
+
"""
|
|
186
|
+
Read until a newline or end of stream.
|
|
187
|
+
|
|
188
|
+
If *size* is given and non-negative, read at most *size* characters.
|
|
189
|
+
The trailing newline is included in the returned string.
|
|
190
|
+
"""
|
|
191
|
+
self._check_closed()
|
|
192
|
+
buflen = len(self._buf)
|
|
193
|
+
if self._pos >= buflen:
|
|
194
|
+
return ''
|
|
195
|
+
nl = self._buf.indexOf('\n', self._pos)
|
|
196
|
+
if nl == -1:
|
|
197
|
+
end = buflen
|
|
198
|
+
else:
|
|
199
|
+
end = nl + 1
|
|
200
|
+
if size is not None and size >= 0:
|
|
201
|
+
limit = self._pos + size
|
|
202
|
+
if limit < end:
|
|
203
|
+
end = limit
|
|
204
|
+
result = self._buf[self._pos:end]
|
|
205
|
+
self._pos = end
|
|
206
|
+
return result
|
|
207
|
+
|
|
208
|
+
def readlines(self, hint=-1):
|
|
209
|
+
"""
|
|
210
|
+
Read and return a list of lines from the stream.
|
|
211
|
+
|
|
212
|
+
*hint* is the approximate number of bytes/characters to read;
|
|
213
|
+
reading stops once the accumulated size reaches or exceeds *hint*.
|
|
214
|
+
"""
|
|
215
|
+
self._check_closed()
|
|
216
|
+
lines = []
|
|
217
|
+
total = 0
|
|
218
|
+
while self._pos < len(self._buf):
|
|
219
|
+
line = self.readline()
|
|
220
|
+
lines.append(line)
|
|
221
|
+
total += len(line)
|
|
222
|
+
if hint is not None and hint >= 0 and total >= hint:
|
|
223
|
+
break
|
|
224
|
+
return lines
|
|
225
|
+
|
|
226
|
+
def write(self, s):
|
|
227
|
+
"""
|
|
228
|
+
Write the string *s* to the stream at the current position.
|
|
229
|
+
|
|
230
|
+
The position is advanced by the number of characters written.
|
|
231
|
+
Returns the number of characters written.
|
|
232
|
+
"""
|
|
233
|
+
self._check_closed()
|
|
234
|
+
s = str(s)
|
|
235
|
+
n = len(s)
|
|
236
|
+
if n == 0:
|
|
237
|
+
return 0
|
|
238
|
+
pos = self._pos
|
|
239
|
+
buflen = len(self._buf)
|
|
240
|
+
if pos >= buflen:
|
|
241
|
+
# Append (may need zero-padding for gaps)
|
|
242
|
+
if pos > buflen:
|
|
243
|
+
# Gap: fill with null characters like Python does
|
|
244
|
+
self._buf += v'"\x00".repeat(pos - buflen)'
|
|
245
|
+
self._buf += s
|
|
246
|
+
else:
|
|
247
|
+
# Overwrite in place (do not extend by skipping)
|
|
248
|
+
self._buf = self._buf[:pos] + s + self._buf[pos + n:]
|
|
249
|
+
self._pos = pos + n
|
|
250
|
+
return n
|
|
251
|
+
|
|
252
|
+
def writelines(self, lines):
|
|
253
|
+
"""Write each item from *lines* to the stream. No newlines are added."""
|
|
254
|
+
self._check_closed()
|
|
255
|
+
for line in lines:
|
|
256
|
+
self.write(line)
|
|
257
|
+
|
|
258
|
+
def seek(self, pos, whence=0):
|
|
259
|
+
"""
|
|
260
|
+
Change the stream position.
|
|
261
|
+
|
|
262
|
+
*whence* controls the reference point:
|
|
263
|
+
0 — absolute position (default)
|
|
264
|
+
1 — relative to the current position
|
|
265
|
+
2 — relative to the end of the stream
|
|
266
|
+
Returns the new absolute position.
|
|
267
|
+
"""
|
|
268
|
+
self._check_closed()
|
|
269
|
+
if whence == 0:
|
|
270
|
+
new_pos = pos
|
|
271
|
+
elif whence == 1:
|
|
272
|
+
new_pos = self._pos + pos
|
|
273
|
+
elif whence == 2:
|
|
274
|
+
new_pos = len(self._buf) + pos
|
|
275
|
+
else:
|
|
276
|
+
raise ValueError('Invalid whence: ' + str(whence))
|
|
277
|
+
self._pos = max(0, new_pos)
|
|
278
|
+
return self._pos
|
|
279
|
+
|
|
280
|
+
def tell(self):
|
|
281
|
+
"""Return the current stream position."""
|
|
282
|
+
self._check_closed()
|
|
283
|
+
return self._pos
|
|
284
|
+
|
|
285
|
+
def truncate(self, pos=None):
|
|
286
|
+
"""
|
|
287
|
+
Truncate the file to at most *pos* characters.
|
|
288
|
+
|
|
289
|
+
If *pos* is omitted or None, truncate at the current position.
|
|
290
|
+
Returns the new size. The stream position is not changed.
|
|
291
|
+
"""
|
|
292
|
+
self._check_closed()
|
|
293
|
+
if pos is None:
|
|
294
|
+
pos = self._pos
|
|
295
|
+
if pos < 0:
|
|
296
|
+
raise ValueError('truncate size must be non-negative')
|
|
297
|
+
self._buf = self._buf[:pos]
|
|
298
|
+
return pos
|
|
299
|
+
|
|
300
|
+
def __iter__(self):
|
|
301
|
+
"""Iterate over lines (starting from the current position)."""
|
|
302
|
+
self._check_closed()
|
|
303
|
+
return iter(self.readlines())
|
|
304
|
+
|
|
305
|
+
def __repr__(self):
|
|
306
|
+
return '<_io.StringIO object>'
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
# ---------------------------------------------------------------------------
|
|
310
|
+
# BytesIO
|
|
311
|
+
# ---------------------------------------------------------------------------
|
|
312
|
+
|
|
313
|
+
class BytesIO(IOBase):
|
|
314
|
+
"""
|
|
315
|
+
In-memory binary stream backed by a bytes buffer.
|
|
316
|
+
|
|
317
|
+
Mirrors the interface of Python's io.BytesIO:
|
|
318
|
+
read([size]) — return up to *size* bytes (-1 or None = all)
|
|
319
|
+
readline([size]) — read one line of bytes
|
|
320
|
+
readlines([hint]) — read all lines as a list of bytes objects
|
|
321
|
+
write(b) — write bytes-like object *b* at current position
|
|
322
|
+
writelines(lines) — write each item in *lines*
|
|
323
|
+
getvalue() — return the full buffer as a bytes object
|
|
324
|
+
seek(pos[, whence]) — reposition (0=absolute, 1=relative, 2=from end)
|
|
325
|
+
tell() — return the current position
|
|
326
|
+
truncate([pos]) — truncate buffer at *pos* (default: current pos)
|
|
327
|
+
close() — mark the stream as closed
|
|
328
|
+
closed — True after close()
|
|
329
|
+
|
|
330
|
+
The *initial_bytes* argument may be a ``bytes``, ``bytearray``,
|
|
331
|
+
``Uint8Array``, or a plain list of integers.
|
|
332
|
+
|
|
333
|
+
Example::
|
|
334
|
+
|
|
335
|
+
bio = BytesIO()
|
|
336
|
+
bio.write(bytes([1, 2, 3]))
|
|
337
|
+
bio.seek(0)
|
|
338
|
+
data = bio.read() # bytes([1, 2, 3])
|
|
339
|
+
|
|
340
|
+
The stream also works as a context manager::
|
|
341
|
+
|
|
342
|
+
with BytesIO(bytes([0x48, 0x69])) as f:
|
|
343
|
+
f.seek(0)
|
|
344
|
+
print(f.read()) # bytes([72, 105])
|
|
345
|
+
"""
|
|
346
|
+
|
|
347
|
+
def __init__(self, initial_bytes=None):
|
|
348
|
+
IOBase.__init__(self)
|
|
349
|
+
self._pos = 0
|
|
350
|
+
if initial_bytes is None:
|
|
351
|
+
self._data = []
|
|
352
|
+
else:
|
|
353
|
+
self._data = v'_io_bytes_to_array(initial_bytes)'
|
|
354
|
+
|
|
355
|
+
def getvalue(self):
|
|
356
|
+
"""Return the entire contents of the buffer as a bytes object."""
|
|
357
|
+
self._check_closed()
|
|
358
|
+
return bytes(self._data)
|
|
359
|
+
|
|
360
|
+
def read(self, size=-1):
|
|
361
|
+
"""
|
|
362
|
+
Read up to *size* bytes from the current position.
|
|
363
|
+
|
|
364
|
+
If *size* is -1 or None, read until end of stream.
|
|
365
|
+
Returns a bytes object.
|
|
366
|
+
"""
|
|
367
|
+
self._check_closed()
|
|
368
|
+
datalen = self._data.length
|
|
369
|
+
if self._pos >= datalen:
|
|
370
|
+
return bytes()
|
|
371
|
+
if size is None or size < 0:
|
|
372
|
+
result = self._data.slice(self._pos)
|
|
373
|
+
self._pos = datalen
|
|
374
|
+
else:
|
|
375
|
+
end = min(self._pos + size, datalen)
|
|
376
|
+
result = self._data.slice(self._pos, end)
|
|
377
|
+
self._pos = end
|
|
378
|
+
return bytes(result)
|
|
379
|
+
|
|
380
|
+
def readline(self, size=-1):
|
|
381
|
+
"""
|
|
382
|
+
Read bytes until a b'\\n' byte or end of stream.
|
|
383
|
+
|
|
384
|
+
If *size* is given and non-negative, read at most *size* bytes.
|
|
385
|
+
The trailing newline byte (0x0a) is included in the result.
|
|
386
|
+
Returns a bytes object.
|
|
387
|
+
"""
|
|
388
|
+
self._check_closed()
|
|
389
|
+
datalen = self._data.length
|
|
390
|
+
if self._pos >= datalen:
|
|
391
|
+
return bytes()
|
|
392
|
+
# search for newline (0x0a)
|
|
393
|
+
end = datalen
|
|
394
|
+
for v'var i = this._pos; i < datalen; i++':
|
|
395
|
+
if self._data[i] == 10:
|
|
396
|
+
end = i + 1
|
|
397
|
+
break
|
|
398
|
+
if size is not None and size >= 0:
|
|
399
|
+
limit = self._pos + size
|
|
400
|
+
if limit < end:
|
|
401
|
+
end = limit
|
|
402
|
+
result = self._data.slice(self._pos, end)
|
|
403
|
+
self._pos = end
|
|
404
|
+
return bytes(result)
|
|
405
|
+
|
|
406
|
+
def readlines(self, hint=-1):
|
|
407
|
+
"""
|
|
408
|
+
Read and return a list of bytes objects, one per line.
|
|
409
|
+
|
|
410
|
+
Reading stops once the accumulated byte count reaches or exceeds *hint*
|
|
411
|
+
(if *hint* is positive).
|
|
412
|
+
"""
|
|
413
|
+
self._check_closed()
|
|
414
|
+
lines = []
|
|
415
|
+
total = 0
|
|
416
|
+
while self._pos < self._data.length:
|
|
417
|
+
line = self.readline()
|
|
418
|
+
lines.append(line)
|
|
419
|
+
total += len(line)
|
|
420
|
+
if hint is not None and hint >= 0 and total >= hint:
|
|
421
|
+
break
|
|
422
|
+
return lines
|
|
423
|
+
|
|
424
|
+
def write(self, b):
|
|
425
|
+
"""
|
|
426
|
+
Write bytes-like object *b* to the stream at the current position.
|
|
427
|
+
|
|
428
|
+
If the write goes past the end of the current buffer, the buffer is
|
|
429
|
+
zero-extended. Returns the number of bytes written.
|
|
430
|
+
"""
|
|
431
|
+
self._check_closed()
|
|
432
|
+
arr = v'_io_bytes_to_array(b)'
|
|
433
|
+
n = arr.length
|
|
434
|
+
if n == 0:
|
|
435
|
+
return 0
|
|
436
|
+
pos = self._pos
|
|
437
|
+
end_pos = pos + n
|
|
438
|
+
# Zero-extend if needed
|
|
439
|
+
while self._data.length < end_pos:
|
|
440
|
+
self._data.push(0)
|
|
441
|
+
for v'var i = 0; i < n; i++':
|
|
442
|
+
self._data[pos + i] = arr[i]
|
|
443
|
+
self._pos = end_pos
|
|
444
|
+
return n
|
|
445
|
+
|
|
446
|
+
def writelines(self, lines):
|
|
447
|
+
"""Write each bytes-like item from *lines* to the stream."""
|
|
448
|
+
self._check_closed()
|
|
449
|
+
for line in lines:
|
|
450
|
+
self.write(line)
|
|
451
|
+
|
|
452
|
+
def seek(self, pos, whence=0):
|
|
453
|
+
"""
|
|
454
|
+
Change the stream position.
|
|
455
|
+
|
|
456
|
+
*whence* controls the reference point:
|
|
457
|
+
0 — absolute position (default)
|
|
458
|
+
1 — relative to the current position
|
|
459
|
+
2 — relative to the end of the stream
|
|
460
|
+
Returns the new absolute position.
|
|
461
|
+
"""
|
|
462
|
+
self._check_closed()
|
|
463
|
+
if whence == 0:
|
|
464
|
+
new_pos = pos
|
|
465
|
+
elif whence == 1:
|
|
466
|
+
new_pos = self._pos + pos
|
|
467
|
+
elif whence == 2:
|
|
468
|
+
new_pos = self._data.length + pos
|
|
469
|
+
else:
|
|
470
|
+
raise ValueError('Invalid whence: ' + str(whence))
|
|
471
|
+
self._pos = max(0, new_pos)
|
|
472
|
+
return self._pos
|
|
473
|
+
|
|
474
|
+
def tell(self):
|
|
475
|
+
"""Return the current stream position."""
|
|
476
|
+
self._check_closed()
|
|
477
|
+
return self._pos
|
|
478
|
+
|
|
479
|
+
def truncate(self, pos=None):
|
|
480
|
+
"""
|
|
481
|
+
Truncate the stream to at most *pos* bytes.
|
|
482
|
+
|
|
483
|
+
If *pos* is omitted or None, truncate at the current position.
|
|
484
|
+
Returns the new size. The stream position is not changed.
|
|
485
|
+
"""
|
|
486
|
+
self._check_closed()
|
|
487
|
+
if pos is None:
|
|
488
|
+
pos = self._pos
|
|
489
|
+
if pos < 0:
|
|
490
|
+
raise ValueError('truncate size must be non-negative')
|
|
491
|
+
self._data = self._data.slice(0, pos)
|
|
492
|
+
return pos
|
|
493
|
+
|
|
494
|
+
def __iter__(self):
|
|
495
|
+
"""Iterate over lines (starting from the current position)."""
|
|
496
|
+
self._check_closed()
|
|
497
|
+
return iter(self.readlines())
|
|
498
|
+
|
|
499
|
+
def __repr__(self):
|
|
500
|
+
return '<_io.BytesIO object>'
|