@@ -119,76 +119,93 @@ public void validate() {
119119
120120 mode .checkValid ();
121121
122- int line_buffering ;
123-
124122 /*
125123 * Create the Raw file stream. Let the constructor deal with the variants and argument
126124 * checking.
127125 */
128126 PyFileIO raw = new PyFileIO (file , mode , closefd );
129127
130- // XXX Can this work: boolean isatty = raw.isatty() ? Or maybe:
131- // PyObject res = PyObject_CallMethod(raw, "isatty", NULL);
132- boolean isatty = false ;
133-
134128 /*
135- * Work out a felicitous buffer size
129+ * From the Python documentation for io.open() buffering = 0 to switch buffering off (only
130+ * allowed in binary mode), 1 to select line buffering (only usable in text mode), and an
131+ * integer > 1 to indicate the size of a fixed-size buffer.
132+ *
133+ * When no buffering argument is given, the default buffering policy works as follows:
134+ * Binary files are buffered in fixed-size chunks; "Interactive" text files (files for which
135+ * isatty() returns True) use line buffering. Other text files use the policy described
136+ * above for binary files.
137+ *
138+ * In Java, it seems a stream never is *known* to be interactive, but we ask anyway, and
139+ * maybe one day we shall know.
136140 */
137- if (buffering == 1 || (buffering < 0 && isatty )) {
138- buffering = -1 ;
139- line_buffering = 1 ;
140- } else {
141- line_buffering = 0 ;
142- }
143-
144- if (buffering < 0 ) {
145- // Try to establish the default buffer size for this file using the OS.
146- buffering = _DEFAULT_BUFFER_SIZE ;
147- // PyObject res = PyObject_CallMethod(raw, "fileno", NULL);
148- // if (fstat(fileno, &st) >= 0 && st.st_blksize > 1)
149- // buffering = st.st_blksize;
150- }
141+ boolean line_buffering = false ;
151142
152- if (buffering < 0 ) {
153- throw Py .ValueError ("invalid buffering size" );
154- }
155-
156- // If not buffering, return the raw file object
157143 if (buffering == 0 ) {
158144 if (!mode .binary ) {
159145 throw Py .ValueError ("can't have unbuffered text I/O" );
160146 }
161147 return raw ;
162- }
163148
164- // We are buffering, so wrap raw into a buffered file
165- PyObject bufferType = null ;
166- PyObject io = imp .load ("io" );
149+ } else if (buffering == 1 ) {
150+ // The stream is to be read line-by-line.
151+ line_buffering = true ;
152+ // Force default size for actual buffer
153+ buffering = -1 ;
167154
168- if (mode .updating ) {
169- bufferType = io .__getattr__ ("BufferedRandom" );
170- } else if (mode .writing || mode .appending ) {
171- bufferType = io .__getattr__ ("BufferedWriter" );
172- } else { // = reading
173- bufferType = io .__getattr__ ("BufferedReader" );
155+ } else if (buffering < 0 && raw .isatty ()) {
156+ // No buffering argument given but stream is inteeractive.
157+ line_buffering = true ;
174158 }
175159
176- PyInteger pyBuffering = new PyInteger (buffering );
177- PyObject buffer = bufferType .__call__ (raw , pyBuffering );
178-
179- // If binary, return the buffered file
180- if (mode .binary ) {
181- return buffer ;
160+ if (buffering < 0 ) {
161+ /*
162+ * We are still being asked for the default buffer size. CPython establishes the default
163+ * buffer size using fstat(fd), but Java appears to give no clue. A useful study of
164+ * buffer sizes in NIO is http://www.evanjones.ca/software/java-bytebuffers.html . This
165+ * leads us to the fixed choice of _DEFAULT_BUFFER_SIZE (=8KB).
166+ */
167+ buffering = _DEFAULT_BUFFER_SIZE ;
182168 }
183169
184- /* We are opening in text mode, so wrap buffer into a TextIOWrapper */
185- PyObject textType = io .__getattr__ ("TextIOWrapper" );
186- PyObject [] textArgs =
187- {buffer , ap .getPyObject (3 , Py .None ), ap .getPyObject (4 , Py .None ),
188- ap .getPyObject (5 , Py .None ), Py .newInteger (line_buffering )};
189- PyObject wrapper = textType .__call__ (textArgs );
190- wrapper .__setattr__ ("mode" , new PyString (m ));
191- return wrapper ;
170+ /*
171+ * We now know just what particular class of file we are opening, and therefore what stack
172+ * (buffering and text encoding) we should build.
173+ */
174+ if (buffering == 0 ) {
175+ // Not buffering, return the raw file object
176+ return raw ;
177+
178+ } else {
179+ // We are buffering, so wrap raw into a buffered file
180+ PyObject bufferType = null ;
181+ PyObject io = imp .load ("io" );
182+
183+ if (mode .updating ) {
184+ bufferType = io .__getattr__ ("BufferedRandom" );
185+ } else if (mode .writing || mode .appending ) {
186+ bufferType = io .__getattr__ ("BufferedWriter" );
187+ } else { // = reading
188+ bufferType = io .__getattr__ ("BufferedReader" );
189+ }
190+
191+ PyInteger pyBuffering = new PyInteger (buffering );
192+ PyObject buffer = bufferType .__call__ (raw , pyBuffering );
193+
194+ if (mode .binary ) {
195+ // If binary, return the just the buffered file
196+ return buffer ;
197+
198+ } else {
199+ // We are opening in text mode, so wrap buffered file in a TextIOWrapper.
200+ PyObject textType = io .__getattr__ ("TextIOWrapper" );
201+ PyObject [] textArgs =
202+ {buffer , ap .getPyObject (3 , Py .None ), ap .getPyObject (4 , Py .None ),
203+ ap .getPyObject (5 , Py .None ), Py .newBoolean (line_buffering )};
204+ PyObject wrapper = textType .__call__ (textArgs );
205+ wrapper .__setattr__ ("mode" , new PyString (m ));
206+ return wrapper ;
207+ }
208+ }
192209 }
193210
194211 private static final String [] openKwds = {"file" , "mode" , "buffering" , "encoding" , "errors" ,
0 commit comments