[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