Skip to content

Commit 9f2b047

Browse files
committed
TextIOWrapper optional args encoding and errors
1 parent fd2e0aa commit 9f2b047

File tree

2 files changed

+61
-4
lines changed

2 files changed

+61
-4
lines changed

vm/src/obj/objstr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ impl PyString {
327327
}
328328

329329
#[pymethod(name = "__repr__")]
330-
fn repr(&self, vm: &VirtualMachine) -> PyResult<String> {
330+
pub(crate) fn repr(&self, vm: &VirtualMachine) -> PyResult<String> {
331331
let in_len = self.value.len();
332332
let mut out_len = 0usize;
333333
// let mut max = 127;

vm/src/stdlib/io.rs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::obj::objbyteinner::PyBytesLike;
1616
use crate::obj::objbytes::PyBytesRef;
1717
use crate::obj::objint;
1818
use crate::obj::objiter;
19-
use crate::obj::objstr::{self, PyStringRef};
19+
use crate::obj::objstr::{self, PyString, PyStringRef};
2020
use crate::obj::objtype::{self, PyClassRef};
2121
use crate::pyobject::{
2222
BufferProtocol, Either, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
@@ -812,12 +812,69 @@ fn buffered_writer_seekable(_self: PyObjectRef) -> bool {
812812
true
813813
}
814814

815+
#[derive(FromArgs)]
816+
struct TextIOWrapperArgs {
817+
#[pyarg(positional_or_keyword, optional = false)]
818+
buffer: PyObjectRef,
819+
#[pyarg(positional_or_keyword, default = "None")]
820+
encoding: Option<PyStringRef>,
821+
#[pyarg(positional_or_keyword, default = "None")]
822+
errors: Option<PyStringRef>,
823+
#[pyarg(positional_or_keyword, default = "None")]
824+
newline: Option<PyStringRef>,
825+
}
826+
827+
impl TextIOWrapperArgs {
828+
fn validate_newline(&self, vm: &VirtualMachine) -> PyResult<()> {
829+
if let Some(pystr) = &self.newline {
830+
match pystr.as_str() {
831+
"" | "\n" | "\r" | "\r\n" => Ok(()),
832+
_ => {
833+
Err(vm.new_value_error(format!("illegal newline value: '{}'", pystr.repr(vm)?)))
834+
}
835+
}
836+
} else {
837+
Ok(())
838+
}
839+
}
840+
}
841+
815842
fn text_io_wrapper_init(
816843
instance: PyObjectRef,
817-
buffer: PyObjectRef,
844+
args: TextIOWrapperArgs,
818845
vm: &VirtualMachine,
819846
) -> PyResult<()> {
820-
vm.set_attr(&instance, "buffer", buffer.clone())?;
847+
args.validate_newline(vm)?;
848+
849+
let mut encoding: Option<PyStringRef> = args.encoding.clone();
850+
let mut self_encoding = None; // TODO: Try os.device_encoding(fileno)
851+
if encoding.is_none() && self_encoding.is_none() {
852+
// TODO: locale module
853+
self_encoding = Some("utf-8");
854+
}
855+
if let Some(self_encoding) = self_encoding {
856+
encoding = Some(PyString::from(self_encoding).into_ref(vm));
857+
} else if let Some(ref encoding) = encoding {
858+
self_encoding = Some(encoding.as_str())
859+
} else {
860+
return Err(vm.new_os_error("could not determine default encoding".to_owned()));
861+
}
862+
let _ = encoding; // TODO: check codec
863+
864+
let errors = args
865+
.errors
866+
.map_or_else(|| vm.ctx.new_str("strict"), |o| o.into_object());
867+
868+
// let readuniversal = args.newline.map_or_else(true, |s| s.as_str().is_empty());
869+
870+
vm.set_attr(
871+
&instance,
872+
"encoding",
873+
self_encoding.map_or_else(|| vm.get_none(), |s| vm.ctx.new_str(s)),
874+
)?;
875+
vm.set_attr(&instance, "errors", errors)?;
876+
vm.set_attr(&instance, "buffer", args.buffer.clone())?;
877+
821878
Ok(())
822879
}
823880

0 commit comments

Comments
 (0)