-
Notifications
You must be signed in to change notification settings - Fork 227
Expand file tree
/
Copy pathPyIOBase.java
More file actions
925 lines (808 loc) · 34 KB
/
PyIOBase.java
File metadata and controls
925 lines (808 loc) · 34 KB
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
/* Copyright (c)2012 Jython Developers */
package org.python.modules._io;
import org.python.core.BufferProtocol;
import org.python.core.Py;
import org.python.core.PyArray;
import org.python.core.PyBUF;
import org.python.core.PyBuffer;
import org.python.core.PyByteArray;
import org.python.core.PyException;
import org.python.core.PyList;
import org.python.core.PyNewWrapper;
import org.python.core.PyObject;
import org.python.core.PyString;
import org.python.core.PyStringMap;
import org.python.core.PyType;
import org.python.core.PyUnicode;
import org.python.core.buffer.SimpleStringBuffer;
import org.python.core.finalization.FinalizableBuiltin;
import org.python.core.finalization.FinalizeTrigger;
import org.python.core.io.FileIO;
import org.python.core.Traverseproc;
import org.python.core.Visitproc;
import org.python.expose.ExposedGet;
import org.python.expose.ExposedMethod;
import org.python.expose.ExposedNew;
import org.python.expose.ExposedSet;
import org.python.expose.ExposedType;
/**
* The Python module <code>_io._IOBase</code>, on which the <code>io</code> module depends directly.
* <p>
* <b>Implementation note:</b> The code is based heavily on the Jython 2.6-ish
* <code>_fileio.PyFileIO</code>, the purely Java-accessible {@link org.python.core.io.IOBase} (both
* Philip Jenvey's work), and the Python implementation in <code>Lib/_pyio</code>. We do not simply
* delegate to the implementation in {@code org.python.core.io} because of the need to override
* parts of the implementation in Python subclasses. A call to {@link #close()}, for example, is
* required to call {@link #flush()}, but if delegated to the pure Java implementation would not
* call the version of <code>flush()</code> overridden in a Python sub-class of
* <code>_io._IOBase</code>. Equally, the use made by <code>PyRawIOBase.read(int)</code> of
* <code>readinto(bytearray)</code> would not pick up the version of <code>readinto</code> defined
* in Python.
*/
@ExposedType(name = "_io._IOBase", doc = PyIOBase.doc)
public class PyIOBase extends PyObject implements FinalizableBuiltin, Traverseproc {
public static final PyType TYPE = PyType.fromClass(PyIOBase.class);
/** The ioDelegate's closer object; ensures the stream is closed at shutdown */
private Closer<PyIOBase> closer;
protected PyIOBase() {
this(TYPE);
FinalizeTrigger.ensureFinalizer(this);
}
protected PyIOBase(PyType subtype) {
super(subtype);
closer = new Closer<PyIOBase>(this, Py.getSystemState());
FinalizeTrigger.ensureFinalizer(this);
}
/**
* Provide a dictionary in the object, so that methods and attributes may be overridden at
* instance level.
*/
@ExposedGet
protected PyStringMap __dict__ = new PyStringMap();
@Override
public PyStringMap fastGetDict() {
return __dict__;
}
@ExposedNew
static PyObject _IOBase___new__(PyNewWrapper new_, boolean init, PyType subtype,
PyObject[] args, String[] keywords) {
if (new_.for_type == subtype) {
// We only want an _io._IOBase, so the constructor does it all
return new PyIOBase();
} else {
// We want some sub-class of it (in which __init__ will be called by the caller)
return new PyIOBaseDerived(subtype);
}
}
/**
* Convenience method returning a PyException(_io.UnsupportedOperation), ripe for throwing, and
* naming the unsupported operation. Like many similar methods, this does not actually throw
* (raise) the exception: it should be thrown from the place where the problem is.
*
* @param op name of operation
* @return the exception for throwing
*/
protected PyException unsupported(String op) {
String fmt = "%s.%s() not supported";
String msg = String.format(fmt, getType().fastGetName(), op);
return _jyio.UnsupportedOperation(msg);
}
@ExposedMethod(doc = "Internal: raise an exception for unsupported operations.")
final void _IOBase__unsupported(String name) {
throw unsupported(name);
}
/**
* Position the read or write pointer at a given byte offset <code>pos</code> relative to a
* position indicated by <code>whence</code>.
* <ul>
* <li>If <code>whence</code>=0, the position will be set to <code>pos</code> bytes.</li>
* <li>If <code>whence</code>=1 the position will be set to the current position plus
* <code>pos</code>.</li>
* <li>If <code>whence</code>=2 the position will be set to the stream size plus
* <code>pos</code> (and usually <code>pos</code><=0).</li>
* </ul>
*
* @param pos relative to the specified point
* @param whence 0=from start, 1=from here, 2=from end
* @return the new current position
*/
public long seek(long pos, int whence) {
return _IOBase_seek(pos, whence);
}
/**
* Position the read or write pointer at a given byte offset <code>pos</code> relative to the
* start.
*
* @param pos relative to the start
* @return the new current position
*/
public final long seek(long pos) {
return seek(pos, 0);
}
@ExposedMethod(defaults = "0", doc = seek_doc)
final long _IOBase_seek(long pos, int whence) {
throw unsupported("seek");
}
/**
* Get the current stream position.
*
* @return stream position
*/
public long tell() {
return _IOBase_tell();
}
@ExposedMethod(doc = tell_doc)
final long _IOBase_tell() {
return seek(0, 1);
}
/**
* Truncate file to <code>size</code> bytes.
*
* @param size requested for stream
* @return the new size
*/
public long truncate(long size) {
return _IOBase_truncate(null); // Just raises an exception anyway
}
/**
* Truncate file to <code>size</code> bytes to the current position (as reported by
* <code>tell()</code>).
*
* @return the new size
*/
public long truncate() {
return _IOBase_truncate(null);
}
@ExposedMethod(defaults = "null", doc = truncate_doc)
final long _IOBase_truncate(PyObject size) {
throw unsupported("truncate");
}
/**
* Flush write buffers, or no-op for read-only and non-blocking streams. Irrespective of the
* concrete type of the i/o object, locally-buffered write data is written downstream. Whether
* the downstream in object is also flushed depends upon the specific type of this object.
*/
public void flush() {
_IOBase_flush();
}
@ExposedMethod(doc = flush_doc)
final void _IOBase_flush() {
// Even types for which this remains a no-op must complain if closed (e.g. BytesIO)
_checkClosed();
}
/**
* True if the object is closed to further <b>client</b> operations. It is the state accessed by
* <code>closed</code> and checked by {@link #_checkClosed()}. It may be set without making it
* an error (for this object and its subclasses) to access some downstream object, notably in
* the implementation of <code>close()</code>.
*/
/*
* This is the analogue of the IS_CLOSED(self) macro and iobase_closed_get() in CPython
* modules/_io/iobase.c. That function checks for the *existence* of an attribute
* __IOBase_closed. You can find this exposed in CPython. _pyio.IOBase exposes _IOBase__closed
* (aka "__closed") for a similar purpose (note different name).
*/
@ExposedGet(name = "closed", doc = closed_doc)
protected boolean __closed;
@ExposedSet(name = "closed")
public final void closed_readonly(boolean value) {
readonlyAttributeError("closed");
}
/**
* Close the stream. If closed already, this is a no-op.
*/
public void close() {
_IOBase_close();
}
@ExposedMethod(doc = close_doc)
final void _IOBase_close() {
if (!__closed) {
/*
* The downstream file (file descriptor) will sometimes have been closed by another
* client. This should raise an error for us, (since data potentially in our buffers
* will be discarded) but we still must end up closed. the local close comes after the
* flush, in case operations within flush() test for "the wrong kind of closed".
*/
try {
// Cancel the wake-up call
closer.dismiss();
// Close should invoke (possibly overridden) flush here.
invoke("flush");
} finally {
// Become closed to further client operations (other than certain enquiries)
__closed = true;
}
}
}
/**
* Is the stream capable of positioning the read/write pointer?
*
* @return <code>True</code> if may be positioned
* @throws PyException {@code ValueError} if the object is closed to client operations
*/
public boolean seekable() throws PyException {
return _IOBase_seekable();
}
@ExposedMethod(doc = seekable_doc)
final boolean _IOBase_seekable() throws PyException {
return false;
}
/**
* Raise an error if the pointer of underlying IO stream <b>is not</b> capable of being
* positioned.
*
* @param msg optional custom message
* @throws PyException {@code ValueError} if the object is closed to client operations
* @throws PyException {@code IOError} if the stream <b>is not</b> capable of being positioned.
*/
public void _checkSeekable(String msg) {
_IOBase__checkSeekable(msg);
}
/**
* Raise an error if the pointer of underlying IO stream <b>is not</b> capable of being
* positioned.
*
* @throws PyException {@code ValueError} if the object is closed to client operations
* @throws PyException {@code IOError} if the stream <b>is not</b> capable of being positioned.
*/
public final void _checkSeekable() {
_checkSeekable(null);
}
@ExposedMethod(defaults = "null")
final void _IOBase__checkSeekable(String msg) {
if (!invoke("seekable").__nonzero__()) {
throw tailoredIOError(msg, "seek");
}
}
/**
* Is the stream readable?
*
* @return <code>true</code> if readable
* @throws PyException {@code ValueError} if the object is closed to client operations
*/
public boolean readable() throws PyException {
return _IOBase_readable();
}
@ExposedMethod(doc = readable_doc)
final boolean _IOBase_readable() throws PyException {
return false;
}
/**
* Raise an error if the underlying IO stream <b>is not</b> readable.
*
* @param msg optional custom message
* @throws PyException {@code ValueError} if the object is closed to client operations
* @throws PyException {@code IOError} if the stream <b>is not</b> readable.
*/
public void _checkReadable(String msg) {
_IOBase__checkReadable(msg);
}
/**
* Raise an error if the underlying IO stream <b>is not</b> readable.
*
* @throws PyException {@code ValueError} if the object is closed to client operations
* @throws PyException {@code IOError} if the stream <b>is not</b> readable.
*/
public final void _checkReadable() {
_checkReadable(null);
}
@ExposedMethod(defaults = "null")
final void _IOBase__checkReadable(String msg) {
if (!invoke("readable").__nonzero__()) {
throw tailoredIOError(msg, "read");
}
}
/**
* Is the stream writable?
*
* @return <code>true</code> if writable
* @throws PyException {@code ValueError} if the object is closed to client operations
*/
public boolean writable() throws PyException {
return _IOBase_writable();
}
@ExposedMethod(doc = writable_doc)
final boolean _IOBase_writable() throws PyException {
return false;
}
/**
* Raise an error if the underlying IO stream <b>is not</b> writable.
*
* @param msg optional custom message
* @throws PyException {@code ValueError} if the object is closed to client operations
* @throws PyException {@code IOError} if the stream <b>is not</b> writable.
*/
public void _checkWritable(String msg) throws PyException {
_IOBase__checkWritable(msg);
}
/**
* Raise an error if the underlying IO stream <b>is not</b> writable.
*
* @throws PyException {@code ValueError} if the object is closed to client operations
* @throws PyException {@code IOError} if the stream <b>is not</b> writable.
*/
public final void _checkWritable() throws PyException {
_checkWritable(null);
}
@ExposedMethod(defaults = "null")
final void _IOBase__checkWritable(String msg) throws PyException {
if (!invoke("writable").__nonzero__()) {
throw tailoredIOError(msg, "writ");
}
}
/**
* Is the stream closed against further client operations?
*
* @return <code>true</code> if closed
*/
public final boolean closed() {
return __closed;
}
/**
* Raise an error if the underlying IO stream <b>is</b> closed. (Note opposite sense from
* {@link #_checkSeekable}, etc..
*
* @param msg optional custom message
* @throws PyException {@code ValueError} if the object is closed to client operations
*/
public void _checkClosed(String msg) throws PyException {
_IOBase__checkClosed(msg);
}
public final void _checkClosed() throws PyException {
_checkClosed(null);
}
@ExposedMethod(defaults = "null")
final void _IOBase__checkClosed(String msg) throws PyException {
if (closed()) {
throw Py.ValueError(msg != null ? msg : "I/O operation on closed file");
}
}
/**
* Called at the start of a context-managed suite (supporting the <code>with</code> clause).
*
* @return this object
*/
public PyObject __enter__() {
return _IOBase___enter__();
}
@ExposedMethod(names = {"__enter__", "__iter__"})
final PyObject _IOBase___enter__() {
_checkClosed();
return this;
}
/**
* Called at the end of a context-managed suite (supporting the <code>with</code> clause), and
* will normally close the stream.
*
* @return false
*/
public boolean __exit__(PyObject type, PyObject value, PyObject traceback) {
return _IOBase___exit__(type, value, traceback);
}
@ExposedMethod
final boolean _IOBase___exit__(PyObject type, PyObject value, PyObject traceback) {
invoke("close");
return false;
}
/**
* Return a file descriptor for the stream. A CPython file descriptor is an int, but this is not
* the natural choice in Jython, since Java has no such convention of using integers. File
* descriptors should be passed around opaquely, so their actual type is irrelevant, as long as
* (say) {@link _jyio#open(PyObject[], String[])} accepts the type that {@link FileIO#fileno()}
* returns.
*
* @return a file descriptor (as opaque object)
*/
public PyObject fileno() {
return _IOBase_fileno();
}
@ExposedMethod(doc = fileno_doc)
final PyObject _IOBase_fileno() {
throw unsupported("fileno");
}
/**
* Is the stream known to be an interactive console? This relies on the ability of the
* underlying stream to know, which is not always possible.
*
* @return <code>true</code> if a console: <code>false</code> if not or we can't tell
*/
public boolean isatty() {
return _IOBase_isatty();
}
@ExposedMethod(doc = isatty_doc)
final boolean _IOBase_isatty() {
_checkClosed();
return false;
}
/**
* Return one line of text (bytes terminates by <code>'\n'</code>), or the specified number of
* bytes, or the whole stream, whichever is shortest.
*
* @param limit maximum number of bytes (<0 means no limit)
* @return the line (or fragment)
*/
public PyObject readline(int limit) {
return _readline(limit);
}
/**
* Return one line of text (bytes terminates by <code>'\n'</code>), or the whole stream,
* whichever is shorter.
*
* @return the line (or fragment)
*/
public PyObject readline() {
return _readline(-1);
}
@ExposedMethod(defaults = "null", doc = readline_doc)
final PyObject _IOBase_readline(PyObject limit) {
if (limit == null || limit == Py.None) {
return _readline(-1);
} else if (limit.isIndex()) {
return _readline(limit.asInt());
} else {
throw tailoredTypeError("integer limit", limit);
}
}
private PyObject _readline(int limit) {
// Either null, or a thing we can __call__()
PyObject peekMethod = __findattr__("peek");
// Either an error, or a thing we can __call__()
PyObject readMethod = __getattr__("read");
// We'll count down from the provided limit here
int remainingLimit = (limit) >= 0 ? limit : Integer.MAX_VALUE;
/*
* We have two almost independent versions of the implementation, depending on whether we
* have a peek() method available.
*/
if (peekMethod != null) {
/*
* This type/object has some kind of read-ahead buffer that we can scan for end of line,
* and refill as required. We are prepared to make a list of the fragments and join them
* at the end, but often there is only one.
*/
PyList list = null;
PyObject curr = Py.EmptyString;
while (remainingLimit > 0) {
// We hope to get away with just one pass of the loop, but if not ...
if (curr.__nonzero__()) {
// We have some previous bytes that must be added to the list
if (list == null) {
// ... be first we need a list to add them to.
list = new PyList();
}
list.add(curr);
}
/*
* peek() returns a str of bytes from the buffer (if any), doing at most one read to
* refill, all without advancing the pointer, or it returns None (in vacuous
* non-blocking read).
*/
PyObject peekResult = peekMethod.__call__(Py.One);
if (peekResult.__nonzero__()) {
// Get a look at the bytes themselves
try (PyBuffer peekBuffer = readablePyBuffer(peekResult)) {
/*
* Scan forwards in the peek buffer to see if there is an end-of-line. Most
* frequently this succeeds. The number of bytes to scan is limited to the
* (remaining) limit value and the peek-buffer length.
*/
int p = 0, nr = peekBuffer.getLen();
if (nr > remainingLimit) {
nr = remainingLimit;
}
while (p < nr) {
if (peekBuffer.byteAt(p++) == '\n') {
remainingLimit = p; // Engineer an exit from the outer loop
break;
}
}
/*
* The the next p bytes should be added to the line we are building, and the
* pointer advanced: that's a read().
*/
curr = readMethod.__call__(Py.newInteger(p));
remainingLimit -= p;
}
} else {
// peekResult was vacuous: we must be finished
curr = Py.EmptyString;
remainingLimit = 0;
}
}
if (list == null) {
// We went through the loop at most once and the entire answer is in curr
return curr;
} else {
// Previous reads are in the list: return them all stitched together
if (curr.__nonzero__()) {
list.add(curr);
}
return Py.EmptyString.join(list);
}
} else {
/*
* We don't have a peek method, so we'll be reading one byte at a time.
*/
PyByteArray res = new PyByteArray();
while (--remainingLimit >= 0) {
/*
* read() returns a str of one byte, doing at most one read to refill, or it returns
* None (in vacuous non-blocking read).
*/
PyObject curr = readMethod.__call__(Py.One);
if (curr.__nonzero__()) {
if (curr instanceof PyString) {
// Should be one-character string holding a byte
char c = ((PyString)curr).getString().charAt(0);
if (c == '\n') {
remainingLimit = 0; // Engineer an exit from the outer loop
}
res.append((byte)c);
} else {
String fmt = "read() should have returned a bytes object, not '%.200s'";
throw Py.IOError(String.format(fmt, curr.getType().fastGetName()));
}
} else {
remainingLimit = 0; // Exit the outer loop
}
}
return res.__str__();
}
}
/**
* Return an iterator on which <code>next</code> may be repeatedly called to produce (usually)
* lines from this stream or file.
*/
@Override
public PyObject __iter__() {
_checkClosed();
// The object *is* an iterator so return itself
return this;
}
// _IOBase___iter__ = _IOBase___enter__
@Override
public PyObject __iternext__() {
PyObject line = invoke("readline");
return (!line.__nonzero__()) ? null : line;
}
/**
* May be called repeatedly to produce (usually) lines from this stream or file.
*
* @return next line from the stream or file
* @throws PyException {@code StopIteration} when iteration has reached a natural conclusion
* @throws PyException {@code ValueError} if the file or stream is closed
* @throws PyException {@code IOError} reflecting an I/O error in during the read
*/
public PyObject next() throws PyException {
return _IOBase_next();
}
@ExposedMethod(doc = "x.__next__() <==> next(x)")
final PyObject _IOBase_next() throws PyException {
// Implement directly. Calling __iternext__() fails when PyIOBaseDerived is considered.
PyObject line = invoke("readline");
if (!line.__nonzero__()) {
throw Py.StopIteration("");
}
return line;
}
/**
* Read a stream as a sequence of lines.
*
* @param hint stop reading lines after this many bytes (if not EOF first)
* @return list containing the lines read
*/
public PyObject readlines(PyObject hint) {
return _IOBase_readlines(hint);
}
@ExposedMethod(defaults = "null", doc = readlines_doc)
final PyObject _IOBase_readlines(PyObject hint) {
int h = 0;
if (hint == null || hint == Py.None) {
return new PyList(this);
} else if (!hint.isIndex()) {
throw tailoredTypeError("integer or None", hint);
} else if ((h = hint.asIndex()) <= 0) {
return new PyList(this);
} else {
int n = 0;
PyList lines = new PyList();
for (PyObject line : this.asIterable()) {
lines.append(line);
n += line.__len__();
if (n >= h) {
break;
}
}
return lines;
}
}
/**
* Write an iterable sequence of strings to the stream.
*
* @param lines
*/
public void writelines(PyObject lines) {
_IOBase_writelines(lines);
}
@ExposedMethod(doc = writelines_doc)
final void _IOBase_writelines(PyObject lines) {
_checkClosed();
// Either an error, or a thing we can __call__()
PyObject writeMethod = __getattr__("write");
for (PyObject line : lines.asIterable()) {
writeMethod.__call__(line);
}
}
@Override
public void __del_builtin__() {
closer.dismiss();
invoke("close");
}
/** Convenience method providing the exception in the _checkWhatever() methods. */
private static PyException tailoredIOError(String msg, String oper) {
if (msg == null) {
return Py.IOError("File or stream is not " + oper + "able.");
} else {
return Py.IOError(msg);
}
}
/**
* Construct a PyBuffer on a given object suitable for writing to the underlying stream. The
* buffer returned will be navigable as a 1D contiguous sequence of bytes.
*
* @param obj to be wrapped and presented as a buffer
* @return a 1D contiguous PyBuffer of bytes
* @throws PyException {@code BufferError} if object has buffer API, but is not 1D contiguous
* bytes
* @throws PyException {@code TypeError} if object not convertible to a byte array
*/
protected static PyBuffer readablePyBuffer(PyObject obj) throws PyException {
// First consider special cases we can view as a String
if (obj instanceof PyUnicode) {
String s = ((PyUnicode) obj).encode();
return new SimpleStringBuffer(PyBUF.SIMPLE, null, s);
} else {
try {
return ((BufferProtocol) obj).getBuffer(PyBUF.SIMPLE);
} catch (PyException pye) {
if (pye.match(Py.BufferError)) {
// If we can't get a buffer on the object, say it's the wrong type
throw Py.TypeError(String.format("(BufferError) %s", pye.getMessage()));
} else {
throw pye;
}
} catch (ClassCastException pye) {
// fall through to message
}
}
// None of the above: complain
throw tailoredTypeError("read-write buffer", obj);
}
/**
* Construct a PyBuffer on a given object suitable for reading into from the underlying stream.
* The buffer returned will be navigable as a 1D contiguous writable sequence of bytes.
*
* @param obj to be wrapped and presented as a buffer
* @return a 1D contiguous PyBuffer of bytes
* @throws PyException {@code BufferError} if object has buffer API, but is not 1D contiguous
* bytes
* @throws PyException {@code TypeError} if object not convertible to a byte array
*/
protected static PyBuffer writablePyBuffer(PyObject obj) throws PyException {
try {
return ((BufferProtocol) obj).getBuffer(PyBUF.WRITABLE);
} catch (PyException pye) {
if (pye.match(Py.BufferError)) {
// If we can't get a buffer on the object, say it's the wrong type
throw Py.TypeError(String.format("(BufferError) %s", pye.getMessage()));
} else {
throw pye;
}
} catch (ClassCastException pye) {
// fall through to message
}
// Can't be a buffer: complain
throw tailoredTypeError("read-write buffer", obj);
}
/**
* Convenience method providing the exception when an argument is not the expected type. The
* format is "<b>type</b> argument expected, got <code>type(arg)</code>."
*
* @param type of thing expected (or could any text)
* @param arg argument provided from which actual type will be reported
* @return TypeError to throw
*/
protected static PyException tailoredTypeError(String type, PyObject arg) {
return Py.TypeError(String.format("%s argument expected, got %.100s.", type, arg.getType()
.fastGetName()));
}
/*
* Documentation strings: public where they might be useful to a subclass.
*/
public static final String seek_doc = "Change stream position.\n" + "\n"
+ "Change the stream position to byte offset offset. offset is\n"
+ "interpreted relative to the position indicated by whence. Values\n"
+ "for whence are:\n" + "\n"
+ "* 0 -- start of stream (the default); offset should be zero or positive\n"
+ "* 1 -- current stream position; offset may be negative\n"
+ "* 2 -- end of stream; offset is usually negative\n" + "\n"
+ "Return the new absolute position.";
public static final String tell_doc = "Return current stream position.";
public static final String truncate_doc = "Truncate file to size bytes.\n" + "\n"
+ "File pointer is left unchanged. Size defaults to the current IO\n"
+ "position as reported by tell(). Returns the new size.";
public static final String flush_doc = "Flush write buffers, if applicable.\n" + "\n"
+ "This is not implemented for read-only and non-blocking streams.";
// public static final String _flush_self_doc =
// "Flush write buffers (if any) into the downstream object\n"
// + "without flushing that object. The base implementations of\n"
// + "flush() and close() will call this method to move any\n"
// + "buffered write-data down to the next i/o object in the\n"
// + "stack before flushing or closing that downstream object.\n"
// + "A sub-class may override this method if it defines buffered\n"
// + "state. Generally sub-classes and clients should not call\n"
// + "this method directly.";
public static final String close_doc = "Flush and close the IO object.\n" + "\n"
+ "This method has no effect if the file is already closed.";
public static final String closed_doc = "True if the stream is closed.\n";
public static final String seekable_doc = "Return whether object supports random access.\n"
+ "\n" + "If False, seek(), tell() and truncate() will raise IOError.\n"
+ "This method may need to do a test seek().";
public static final String readable_doc = "Return whether object was opened for reading.\n"
+ "\n" + "If False, read() will raise IOError.";
public static final String writable_doc = "Return whether object was opened for writing.\n"
+ "\n" + "If False, read() will raise IOError.";
public static final String fileno_doc = "Returns underlying file descriptor if one exists.\n"
+ "\n" + "An IOError is raised if the IO object does not use a file descriptor.\n";
public static final String isatty_doc = "Return whether this is an 'interactive' stream.\n"
+ "\n" + "Return False if it can't be determined.\n";
public static final String readline_doc = "Read and return a line from the stream.\n" + "\n"
+ "If limit is specified, at most limit bytes will be read.\n" + "\n"
+ "The line terminator is always b'\n' for binary files; for text\n"
+ "files, the newlines argument to open can be used to select the line\n"
+ "terminator(s) recognized.\n";
public static final String readlines_doc = "Return a list of lines from the stream.\n" + "\n"
+ "hint can be specified to control the number of lines read: no more\n"
+ "lines will be read if the total size (in bytes/characters) of all\n"
+ "lines so far exceeds hint.";
public static final String writelines_doc =
"Write a list of lines to the stream. Line separators are not added,\n"
+ "so it is usual for each of the lines provided to have a line separator\n"
+ "at the end.";
static final String doc = "The abstract base class for all I/O classes, acting on streams of\n"
+ "bytes. There is no public constructor.\n" + "\n"
+ "This class provides dummy implementations for many methods that\n"
+ "derived classes can override selectively; the default implementations\n"
+ "represent a file that cannot be read, written or seeked.\n" + "\n"
+ "Even though IOBase does not declare read, readinto, or write because\n"
+ "their signatures will vary, implementations and clients should\n"
+ "consider those methods part of the interface. Also, implementations\n"
+ "may raise a IOError when operations they do not support are called.\n" + "\n"
+ "The basic type used for binary data read from or written to a file is\n"
+ "bytes. bytearrays are accepted too, and in some cases (such as\n"
+ "readinto) needed. Text I/O classes work with str data.\n" + "\n"
+ "Note that calling any method (even inquiries) on a closed stream is\n"
+ "undefined. Implementations may raise IOError in this case.\n" + "\n"
+ "IOBase (and its subclasses) support the iterator protocol, meaning\n"
+ "that an IOBase object can be iterated over yielding the lines in a\n" + "stream.\n"
+ "\n" + "IOBase also supports the :keyword:`with` statement. In this example,\n"
+ "fp is closed after the suite of the with statement is complete:\n" + "\n"
+ "with open('spam.txt', 'r') as fp:\n" + " fp.write('Spam and eggs!')\n";
/* Traverseproc implementation */
@Override
public int traverse(Visitproc visit, Object arg) {
// closer cannot be null
if (closer.sys != null) {
int retVal = visit.visit(closer.sys, arg);
if (retVal != 0) {
return retVal;
}
}
// __dict__ cannot be null
return visit.visit(__dict__, arg);
}
@Override
public boolean refersDirectlyTo(PyObject ob) {
return ob != null && (ob == closer.sys || ob == __dict__);
}
}