from . import libfields


class Error(Exception):
    """
    This exception is raised whenever an error is detected.
    """
    pass


def reader(source, **kwargs):
    """
    Return a reader object that reads from `source`. `source` can be either a
    string or a file object. If `source` is a file object, it should be opened
    with the `b` flag.

    Optional keyword arguments can be given to override default formatting
    parameters:

      - `delimiter`: a one-character string used to separate fields. It
        defaults to `,`.

      - `quotechar`: a one-character string used to quote fields containing
        special characters, such as the `delimiter` or the `quotechar`. It
        defaults to `"`.

    The returned object is an iterator. Each iteration returns a record, a
    sequence of fields. Records are implemented as lists of strings.
    """
    return Reader(source, **kwargs)


class Reader(object):

    def __init__(self, source, **kwargs):
        fmt, settings = _parse(kwargs)
        try:
            self.__reader = libfields.Reader(source, fmt, settings)
            self.__record = libfields.Record(settings)
        except ValueError as e:
            raise Error(str(e))

    def __iter__(self):
        return self

    def next(self):
        result = self.__reader.read(self.__record)
        if result != 0:
            result = self.__reader.error()
            if result:
                raise Error(result)
            else:
                raise StopIteration
        return [self.__record.field(i) for i in xrange(self.__record.size())]


def _parse(kwargs):
        def as_char(value):
            return value or '\0'
        def as_int(value):
            return int(bool(value))
        fmt = libfields.Format(
            delimiter = as_char(kwargs.get('delimiter', ',')),
            quote = as_char(kwargs.get('quotechar', '"'))
        )
        settings = libfields.Settings(
            expand = as_int(kwargs.get('_expand', True)),
            source_buffer_size = kwargs.get('_source_buffer_size', 4 * 1024),
            record_buffer_size = kwargs.get('_record_buffer_size', 1024 * 1024),
            record_max_fields = kwargs.get('_record_max_fields', 1023)
        )
        return (fmt, settings)

@@ -978,25 +978,47 @@
 %0A        fmt
-,
+ = _fmt(kwargs)%0A       
  settings = 
@@ -1018,21 +1018,24 @@
 ings = _
-parse
+settings
 (kwargs)
@@ -1621,160 +1621,32 @@
 ef _
-parse(kwargs):%0A        def as_char(value):%0A            return value or '%5C0'%0A        def as_int(value):%0A            return int(bool(value))%0A        fmt =
+fmt(options):%0A    return
  lib
@@ -1668,20 +1668,16 @@
         
-    
 delimite
@@ -1680,29 +1680,22 @@
 miter = 
-as_char(kwarg
+option
 s.get('d
@@ -1709,23 +1709,26 @@
 r', ',')
-),%0A    
+ or '%5C0',%0A
         
@@ -1737,23 +1737,20 @@
 ote 
-= as_char(kwarg
+    = option
 s.ge
@@ -1772,38 +1772,59 @@
 '%22')
-)%0A        )%0A        settings =
+ or '%5C0',%0A    )%0A%0Adef _settings(options):%0A    return
  lib
@@ -1852,33 +1852,39 @@
     
- 
-   
 expand 
-= as_int(kwarg
+            = int(option
 s.ge
@@ -1912,20 +1912,16 @@
         
-    
 source_b
@@ -1925,37 +1925,38 @@
 e_buffer_size = 
-kwarg
+option
 s.get('_source_b
@@ -1983,28 +1983,24 @@
 4),%0A        
- 
-   
 record_buffe
@@ -2008,21 +2008,22 @@
 _size = 
-kwarg
+option
 s.get('_
@@ -2061,28 +2061,24 @@
 4),%0A        
-    
 record_max_f
@@ -2087,15 +2087,17 @@
 lds 
+ 
 = 
-kwarg
+option
 s.ge
@@ -2129,46 +2129,12 @@
 023)
+,
 %0A    
-    )%0A        return (fmt, settings
 )%0A

Extract '_fmt' and '_settings' from '_parse'