Repository: frictionlessdata/tabulator-py (python)

Issue:
Rename topen argument with_headers to extract_headers
# Overview

`with_headers` argument is just confusing (based on experience of `jsontableschema.Resource` work) . So it's a part of consistent v1 API work. Changes should be made with adding backward-compatibility code to support `with_headers` argument before v1.

Pull request description:
Renamed with_headers to extract_headers
It fixes #66 

Patch:
diff --git a/README.md b/README.md
index 4cfb1d3..0303532 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ Fast access to the table with `topen` (stands for `table open`) function:
 ```python
 from tabulator import topen, processors
 
-with topen('path.csv', with_headers=True) as table:
+with topen('path.csv', extract_headers=True) as table:
     for row in table:
         print(row)  # will print row tuple
 ```
@@ -50,7 +50,7 @@ with `limit` of output rows as parameter.
 - table pointer can be set to start via `reset` method.
 
 In the example above we use `processors.Headers` to extract headers
-from the table (via `with_headers=True` shortcut). Processors is a powerfull
+from the table (via `extract_headers=True` shortcut). Processors is a powerfull
 Tabulator concept. Parsed data goes thru pipeline of processors to be updated before
 returning as table row.
 
@@ -146,17 +146,20 @@ class MyProcessor(processors.API):
 
 ## Changelog
 
+```
 - 0.5.0
-  - BREAKING CHANGE: updated `loaders.API` and `parsers.API`
-  - BREAKING CHANGE: moved topen `loader_class` argument to `loader_options` argument as `constructor` key
-  - BREAKING CHANGE: moved topen `parser_class` argument to `parser_options` argument as `constructor` key
-  - BREAKING CHANGE: removed topen `table_class` argument
-  - BREAKING CHANGE: removed topen `iterator_class` argument
-  - BREAKING CHANGE: removed topen `row_class` argument
-  - BREAKING CHANGE: removed `processors.Schema`
-  - BREAKING CHANGE: removed `Row`
-  - added `Table.iter(keyed=False)`
-  - added `processors.Convert`
+  - BREAKING CHANGE: updated loaders.API and parsers.API
+  - BREAKING CHANGE: renamed topen argument with_headers to extract_headers
+  - BREAKING CHANGE: moved topen loader_class argument to loader_options argument as constructor key
+  - BREAKING CHANGE: moved topen parser_class argument to parser_options argument as constructor key
+  - BREAKING CHANGE: removed topen table_class argument
+  - BREAKING CHANGE: removed topen iterator_class argument
+  - BREAKING CHANGE: removed topen row_class argument
+  - BREAKING CHANGE: removed processors.Schema
+  - BREAKING CHANGE: removed Row
+  - added Table.iter(keyed=False)
+  - added processors.Convert
+```
 
 ## Contributing
 
diff --git a/examples/topen.py b/examples/topen.py
index ff75841..9a8bc70 100644
--- a/examples/topen.py
+++ b/examples/topen.py
@@ -11,7 +11,7 @@ from tabulator import topen, loaders, parsers, processors
 
 print('Parse csv format:')
 source = 'data/table.csv'
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     print(table.headers)
     for row in table:
         print(row)
@@ -19,7 +19,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nParse linear tsv format:')
 source = 'data/table.tsv'
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     print(table.headers)
     for row in table:
         print(row)
@@ -27,7 +27,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nParse json with dicts:')
 source = 'file://data/table-dicts.json'
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     print(table.headers)
     for row in table:
         print(row)
@@ -35,7 +35,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nParse json with lists:')
 source = 'file://data/table-lists.json'
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     print(table.headers)
     for row in table:
         print(row)
@@ -43,7 +43,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nParse xls format:')
 source = 'data/table.xls'
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     print(table.headers)
     for row in table:
         print(row)
@@ -51,7 +51,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nParse xlsx format:')
 source = 'data/table.xlsx'
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     print(table.headers)
     for row in table:
         print(row)
@@ -59,7 +59,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nLoad from stream scheme:')
 source = io.open('data/table.csv', mode='rb')
-with topen(source, with_headers=True, format='csv') as table:
+with topen(source, extract_headers=True, format='csv') as table:
     print(table.headers)
     for row in table:
         print(row)
@@ -67,7 +67,7 @@ with topen(source, with_headers=True, format='csv') as table:
 
 print('\nLoad from text scheme:')
 source = 'text://id,name\n1,english\n2,中国人\n'
-with topen(source, with_headers=True, format='csv') as table:
+with topen(source, extract_headers=True, format='csv') as table:
     print(table.headers)
     for row in table:
         print(row)
@@ -76,7 +76,7 @@ with topen(source, with_headers=True, format='csv') as table:
 print('\nLoad from http scheme:')
 source = 'https://raw.githubusercontent.com'
 source += '/okfn/tabulator-py/master/data/table.csv'
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     print(table.headers)
     for row in table:
         print(row)
@@ -84,7 +84,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nUsage of native lists:')
 source = [['id', 'name'], ['1', 'english'], ('2', '中国人')]
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     print(table.headers)
     for row in table:
         print(row)
@@ -92,7 +92,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nUsage of native lists (keyed):')
 source = [{'id': '1', 'name': 'english'}, {'id': '2', 'name': '中国人'}]
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     print(table.headers)
     for row in table:
         print(row)
@@ -100,7 +100,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nIter with keyed rows representation:')
 source = [{'id': '1', 'name': 'english'}, {'id': '2', 'name': '中国人'}]
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     print(table.headers)
     for row in table.iter(keyed=True):
         print(row)
@@ -108,7 +108,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nTable reset and read limit:')
 source = 'data/table.csv'
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     print(table.headers)
     print(table.read(limit=1))
     table.reset()
@@ -126,7 +126,7 @@ with topen(source) as table:
 
 print('\nBad headers (skip):')
 source = 'data/special/bad_headers.json'
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     table.add_processor(processors.Strict(skip=True))
     print(table.headers)
     for row in table:
@@ -135,7 +135,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nBad headers (raise):')
 source = 'data/special/bad_headers.json'
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     table.add_processor(processors.Strict())
     print(table.headers)
     try:
@@ -146,7 +146,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nBad dimension (raise):')
 source = 'data/special/bad_dimension.csv'
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     table.add_processor(processors.Strict())
     try:
         table.read()
@@ -156,7 +156,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nBad headers dimension (raise):')
 source = 'data/special/bad_headers_dimension.csv'
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     table.add_processor(processors.Strict())
     try:
         table.read()
@@ -166,7 +166,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nUsing convert processor:')
 source = 'data/table.csv'
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     table.add_processor(processors.Convert())
     print(table.headers)
     for row in table:
@@ -175,7 +175,7 @@ with topen(source, with_headers=True) as table:
 
 print('\nSpaces in headers:')
 source = 'https://raw.githubusercontent.com/datasets/gdp/master/data/gdp.csv'
-with topen(source, with_headers=True) as table:
+with topen(source, extract_headers=True) as table:
     print(table.headers)
     for row in table.read(limit=5):
         print(row)
diff --git a/tabulator/topen.py b/tabulator/topen.py
index 3849f8d..6b8ec6e 100644
--- a/tabulator/topen.py
+++ b/tabulator/topen.py
@@ -20,11 +20,12 @@ def topen(source,
           encoding=None,
           loader_options=None,
           parser_options=None,
+          extract_headers=False,
           processors=None,
-          with_headers=False,
           # BACKWARD-COMPATIBILITY (before v0.5)
           loader_class=None,
-          parser_class=None):
+          parser_class=None,
+          with_headers=False):
     """Open table from source.
 
     Args:
@@ -62,8 +63,8 @@ def topen(source,
             parser options:
                 `constructor`: constructor returning `parsers.API` instance
                 <backend options>
+        extract_headers (bool): extract table headers
         processors (list): processors to add to the pipeline
-        with_headers (bool): extract headers
 
     Returns:
         table (Table): opened table instance
@@ -80,6 +81,7 @@ def topen(source,
         loader_options['constructor'] = loader_class
     if parser_class is not None:
         parser_options['constructor'] = parser_class
+    extract_headers = extract_headers or with_headers
 
     # Get loader
     loader_constructor = loader_options.pop('constructor', None)
@@ -108,7 +110,7 @@ def topen(source,
     table.open()
 
     # Add headers processor
-    if with_headers:
+    if extract_headers:
         table.add_processor(Headers())
 
     # Add user processors


Test patch:
diff --git a/tests/test_topen.py b/tests/test_topen.py
index 55f9d6c..220e652 100644
--- a/tests/test_topen.py
+++ b/tests/test_topen.py
@@ -207,6 +207,18 @@ class Test_topen(unittest.TestCase):
 
     # Tests [processors]
 
+    def test_headers(self):
+
+        # Get table
+        table = topen(FPATH % 'table.csv', extract_headers=True)
+
+        # Make assertions
+        assert table.headers == ('id', 'name')
+        assert list(table.iter(keyed=True)) == [
+            {'id': '1', 'name': 'english'},
+            {'id': '2', 'name': '中国人'}]
+
+    # BACKWARD-COMPATIBILITY (before v0.5)
     def test_headers(self):
 
         # Get table
@@ -221,7 +233,7 @@ class Test_topen(unittest.TestCase):
     def test_headers_via_processors_param(self):
 
         # Get results
-        table = topen(FPATH % 'table.csv', with_headers=True,
+        table = topen(FPATH % 'table.csv', extract_headers=True,
             processors=[processors.Headers()])
 
         # Make assertions
@@ -236,7 +248,7 @@ class Test_topen(unittest.TestCase):
         source = ('text://['
             '{"id": 1, "name": "english"},'
             '{"id": 2, "value": "中国人"}]')
-        table = topen(source, with_headers=True, format='json')
+        table = topen(source, extract_headers=True, format='json')
 
         # Make assertions
         assert table.headers == ('id', 'name')
@@ -248,7 +260,7 @@ class Test_topen(unittest.TestCase):
 
         # Get table
         source = [{'id': '1', 'name': 'english'}, {'id': '2', 'name': '中国人'}]
-        table = topen(source, with_headers=True)
+        table = topen(source, extract_headers=True)
 
         # Make assertions
         assert table.headers == ('id', 'name')
@@ -258,7 +270,7 @@ class Test_topen(unittest.TestCase):
 
         # Get table
         source = [['id', 'name'], ['1', 'english'], ('2', '中国人')]
-        table = topen(source, with_headers=True)
+        table = topen(source, extract_headers=True)
 
         # Make assertions
         assert table.headers == ('id', 'name')
@@ -272,7 +284,7 @@ class Test_topen(unittest.TestCase):
 
         # Get table
         table = topen(FPATH % 'table.csv',
-            with_headers=True, processors=[processors.Convert()])
+            extract_headers=True, processors=[processors.Convert()])
 
         # Make assertions
         assert table.headers == ('id', 'name')
@@ -284,7 +296,7 @@ class Test_topen(unittest.TestCase):
         def converter(values):
             return [float(values[0]), values[1]]
         table = topen(FPATH % 'table.csv',
-            with_headers=True, processors=[processors.Convert(converter)])
+            extract_headers=True, processors=[processors.Convert(converter)])
 
         # Make assertions
         assert table.headers == ('id', 'name')
@@ -295,7 +307,7 @@ class Test_topen(unittest.TestCase):
     def test_reset(self):
 
         # Get results
-        with topen(FPATH % 'table.csv', with_headers=True) as table:
+        with topen(FPATH % 'table.csv', extract_headers=True) as table:
             headers1 = table.headers
             contents1 = table.read()
             table.reset()