[pypy-commit] pypy default: in-progress
arigo
noreply at buildbot.pypy.org
Mon Sep 24 18:10:21 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r57497:77e53dea1fe0
Date: 2012-09-23 17:28 +0200
http://bitbucket.org/pypy/pypy/changeset/77e53dea1fe0/
Log: in-progress
diff --git a/pypy/module/_csv/__init__.py b/pypy/module/_csv/__init__.py
--- a/pypy/module/_csv/__init__.py
+++ b/pypy/module/_csv/__init__.py
@@ -80,5 +80,5 @@
'Dialect': 'interp_csv.W_Dialect',
- 'Reader': 'interp_reader.W_Reader',
+ 'reader': 'interp_reader.csv_reader',
}
diff --git a/pypy/module/_csv/interp_csv.py b/pypy/module/_csv/interp_csv.py
--- a/pypy/module/_csv/interp_csv.py
+++ b/pypy/module/_csv/interp_csv.py
@@ -9,8 +9,17 @@
class W_Dialect(Wrappable):
- pass
-
+ _immutable_fields_ = [
+ "dialect",
+ "delimiter",
+ "doublequote",
+ "escapechar",
+ "lineterminator",
+ "quotechar",
+ "quoting",
+ "skipinitialspace",
+ "strict",
+ ]
def _fetch(space, w_dialect, name):
return space.findattr(w_dialect, space.wrap(name))
@@ -43,31 +52,25 @@
raise operationerrfmt(space.w_TypeError,
'"%s" must be a 1-character string', name)
-def W_Dialect___new__(space, w_subtype, w_dialect = NoneNotWrapped,
- w_delimiter = NoneNotWrapped,
- w_doublequote = NoneNotWrapped,
- w_escapechar = NoneNotWrapped,
- w_lineterminator = NoneNotWrapped,
- w_quotechar = NoneNotWrapped,
- w_quoting = NoneNotWrapped,
- w_skipinitialspace = NoneNotWrapped,
- w_strict = NoneNotWrapped,
- ):
+def _build_dialect(space, w_dialect, w_delimiter, w_doublequote,
+ w_escapechar, w_lineterminator, w_quotechar, w_quoting,
+ w_skipinitialspace, w_strict):
if w_dialect is not None:
if space.isinstance_w(w_dialect, space.w_basestring):
w_module = space.getbuiltinmodule('_csv')
w_dialect = space.call_method(w_module, 'get_dialect', w_dialect)
- if (w_delimiter is None and
+ dialect = space.interpclass_w(w_dialect)
+ if (isinstance(dialect, W_Dialect) and
+ w_delimiter is None and
w_doublequote is None and
w_escapechar is None and
w_lineterminator is None and
w_quotechar is None and
w_quoting is None and
w_skipinitialspace is None and
- w_strict is None and
- space.is_w(w_subtype, space.type(w_dialect))):
- return w_dialect
+ w_strict is None):
+ return dialect
if w_delimiter is None:
w_delimiter = _fetch(space, w_dialect, 'delimiter')
@@ -86,7 +89,7 @@
if w_strict is None:
w_strict = _fetch(space, w_dialect, 'strict')
- dialect = space.allocate_instance(W_Dialect, w_subtype)
+ dialect = W_Dialect()
dialect.delimiter = _get_char(space, w_delimiter, ',', 'delimiter')
dialect.doublequote = _get_bool(space, w_doublequote, True)
dialect.escapechar = _get_char(space, w_escapechar, '\0', 'escapechar')
@@ -111,8 +114,34 @@
raise OperationError(space.w_TypeError,
space.wrap('quotechar must be set if quoting enabled'))
dialect.quoting = tmp_quoting
+ return dialect
- return space.wrap(dialect)
+def W_Dialect___new__(space, w_subtype, w_dialect = NoneNotWrapped,
+ w_delimiter = NoneNotWrapped,
+ w_doublequote = NoneNotWrapped,
+ w_escapechar = NoneNotWrapped,
+ w_lineterminator = NoneNotWrapped,
+ w_quotechar = NoneNotWrapped,
+ w_quoting = NoneNotWrapped,
+ w_skipinitialspace = NoneNotWrapped,
+ w_strict = NoneNotWrapped,
+ ):
+ dialect = _build_dialect(space, w_dialect, w_delimiter, w_doublequote,
+ w_escapechar, w_lineterminator, w_quotechar,
+ w_quoting, w_skipinitialspace, w_strict)
+ if space.is_w(w_subtype, space.gettypeobject(W_Dialect.typedef)):
+ return space.wrap(dialect)
+ else:
+ subdialect = space.allocate_instance(W_Dialect, w_subtype)
+ subdialect.delimiter = dialect.delimiter
+ subdialect.doublequote = dialect.doublequote
+ subdialect.escapechar = dialect.escapechar
+ subdialect.lineterminator = dialect.lineterminator
+ subdialect.quotechar = dialect.quotechar
+ subdialect.quoting = dialect.quoting
+ subdialect.skipinitialspace = dialect.skipinitialspace
+ subdialect.strict = dialect.strict
+ return space.wrap(subdialect)
def _get_escapechar(space, dialect):
diff --git a/pypy/module/_csv/interp_reader.py b/pypy/module/_csv/interp_reader.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_csv/interp_reader.py
@@ -0,0 +1,111 @@
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import NoneNotWrapped
+from pypy.interpreter.typedef import TypeDef, interp2app
+from pypy.module._csv.interp_csv import (QUOTE_MINIMAL, QUOTE_ALL,
+ QUOTE_NONNUMERIC, QUOTE_NONE)
+
+(START_RECORD, START_FIELD, ESCAPED_CHAR, IN_FIELD,
+ IN_QUOTED_FIELD, ESCAPE_IN_QUOTED_FIELD, QUOTE_IN_QUOTED_FIELD,
+ EAT_CRNL) = range(8)
+
+
+def error(space, msg):
+ w_module = space.getbuiltinmodule('_csv')
+ w_error = space.getattr(w_module, space.wrap('Error'))
+ raise OperationError(w_error, space.wrap(msg))
+
+
+class W_Reader(Wrappable):
+
+ def __init__(self, space, dialect, w_iter):
+ self.space = space
+ self.dialect = dialect
+ self.w_iter = w_iter
+ self.line_num = 0
+
+ def iter_w(self):
+ return self.space.wrap(self)
+
+ def next_w(self):
+ space = self.space
+ dialect = self.dialect
+ self.fields_w = []
+ self.numeric_field = False
+ field = ''
+ state = START_RECORD
+ #
+ while True:
+ try:
+ w_line = space.next(self.w_iter)
+ except OperationError, e:
+ if e.match(space, space.w_StopIteration) and len(field) > 0:
+ raise error("newline inside string")
+ raise
+ self.line_num += 1
+ line = space.str_w(w_line)
+ for c in line:
+ if state == START_RECORD:
+ if c == '\n' or c == '\r':
+ state = EAT_CRNL
+ continue
+ # normal character - handle as START_FIELD
+ state = START_FIELD
+ if state == START_FIELD:
+ # expecting field
+ if c == '\n' or c == '\r':
+ # save empty field
+ assert len(field) == 0; self.save_field('')
+ state = EAT_CRNL
+ elif (c == dialect.quotechar and
+ dialect.quoting != QUOTE_NONE):
+ # start quoted field
+ state = IN_QUOTED_FIELD
+ elif c == dialect.escapechar:
+ # possible escaped character
+ state = ESCAPED_CHAR
+ elif c == ' ' and dialect.skipinitialspace:
+ # ignore space at start of field
+ pass
+ elif c == dialect.delimiter:
+ # save empty field
+ assert len(field) == 0; self.save_field('')
+ else:
+ # begin new unquoted field
+ if dialect.quoting == QUOTE_NONNUMERIC:
+ self.numeric_field = True
+ field += .....
+ #
+ w_result = space.newlist(self.fields_w)
+ self.fields_w = None
+ return w_result
+
+
+def csv_reader(space, w_iterator, w_dialect=NoneNotWrapped,
+ w_delimiter = NoneNotWrapped,
+ w_doublequote = NoneNotWrapped,
+ w_escapechar = NoneNotWrapped,
+ w_lineterminator = NoneNotWrapped,
+ w_quotechar = NoneNotWrapped,
+ w_quoting = NoneNotWrapped,
+ w_skipinitialspace = NoneNotWrapped,
+ w_strict = NoneNotWrapped,
+ ):
+ w_iter = space.iter(w_iterator)
+ dialect = _build_dialect(space, w_dialect, w_delimiter, w_doublequote,
+ w_escapechar, w_lineterminator, w_quotechar,
+ w_quoting, w_skipinitialspace, w_strict)
+ return W_Reader(space, dialect, w_iter)
+
+W_Reader.typedef = TypeDef(
+ 'reader',
+ __module__ = '_csv',
+ dialect = interp_attrproperty_w('dialect', W_Reader),
+ line_num = interp_attrproperty('line_num', W_Reader),
+ __iter__ = interp2app(W_Reader.iter_w),
+ next = interp2app(W_Reader.next_w),
+ __doc__ = """CSV reader
+
+Reader objects are responsible for reading and parsing tabular data
+in CSV format.""")
+W_Reader.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_csv/test/test_reader.py b/pypy/module/_csv/test/test_reader.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_csv/test/test_reader.py
@@ -0,0 +1,12 @@
+from pypy.conftest import gettestobjspace
+
+
+class AppTestReader(object):
+ def setup_class(cls):
+ cls.space = gettestobjspace(usemodules=['_csv'])
+
+ def test_simple_reader(self):
+ import _csv
+ r = _csv.reader(['foo:bar\n'], delimiter=':')
+ lst = list(r)
+ assert lst == [['foo', 'bar']]
More information about the pypy-commit
mailing list