Skip to content

Commit 6b44f6c

Browse files
committed
Use backports.csv rather than unicodecsv #280
* and fix tests accordingly Signed-off-by: Philippe Ombredanne <[email protected]>
1 parent db4c37b commit 6b44f6c

16 files changed

+108
-89
lines changed

etc/conf/base.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ six
1616

1717
pyyaml==3.12
1818

19-
unicodecsv==0.14.1
19+
backports.csv==1.0.5
2020

2121
# license expression support
2222
license_expression

src/attributecode/cmd.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import sys
2626

2727
import click
28-
import unicodecsv
2928

3029
import attributecode
3130
from attributecode import CRITICAL

src/attributecode/gen.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,8 @@
2222
from collections import OrderedDict
2323
import logging
2424
import posixpath
25-
import sys
2625

27-
if sys.version_info >= (3, 0):
28-
from unicodecsv.py3 import UnicodeReader
29-
else:
30-
from unicodecsv.py2 import UnicodeReader
26+
import backports.csv as csv
3127

3228
from attributecode import ERROR
3329
from attributecode import CRITICAL
@@ -55,7 +51,7 @@ def check_duplicated_columns(location):
5551
"""
5652
location = add_unc(location)
5753
with codecs.open(location, 'rb', encoding='utf-8', errors='ignore') as csvfile:
58-
reader = UnicodeReader(csvfile)
54+
reader = csv.reader(csvfile)
5955
columns = reader.next()
6056
columns = [col for col in columns]
6157

src/attributecode/model.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
from posixpath import dirname
3737
import re
3838

39+
import backports.csv as csv
3940
from license_expression import Licensing
40-
import unicodecsv
4141

4242
try:
4343
import urllib2 # Python 2
@@ -1294,7 +1294,7 @@ def write_output(abouts, location, format, with_absent=False, with_empty=True):
12941294
with codecs.open(location, mode='wb', encoding='utf-8') as output_file:
12951295
if format == 'csv':
12961296
fieldnames = field_names(abouts)
1297-
writer = unicodecsv.DictWriter(output_file, fieldnames)
1297+
writer = csv.DictWriter(output_file, fieldnames)
12981298
writer.writeheader()
12991299
for row in about_dictionary_list:
13001300
# See https://github.com/dejacode/about-code-tool/issues/167

src/attributecode/util.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
import string
3333
import sys
3434

35-
import unicodecsv
35+
import backports.csv as csv
3636

3737
try:
3838
import httplib # Python 2
@@ -230,12 +230,12 @@ def resource_name(path):
230230
return right.strip()
231231

232232

233-
class OrderedDictReader(unicodecsv.DictReader):
233+
class OrderedDictReader(csv.DictReader):
234234
"""
235235
A DictReader that return OrderedDicts
236236
"""
237237
def next(self):
238-
row_dict = unicodecsv.DictReader.next(self)
238+
row_dict = csv.DictReader.next(self)
239239
result = OrderedDict()
240240
# reorder based on fieldnames order
241241
for name in self.fieldnames:
@@ -253,7 +253,7 @@ def get_mappings(location=None):
253253
location = abspath(dirname(__file__))
254254
mappings = {}
255255
try:
256-
with open(join(location, 'mapping.config'), 'rU') as mapping_file:
256+
with open(join(location, 'mapping.config')) as mapping_file:
257257
for line in mapping_file:
258258
if not line or not line.strip() or line.strip().startswith('#'):
259259
continue
@@ -282,7 +282,7 @@ def apply_mappings(abouts, mappings=None):
282282
mappings = mappings or get_mappings()
283283
mapped_abouts = []
284284
for about in abouts:
285-
mapped_about = {}
285+
mapped_about = OrderedDict()
286286
for key in about:
287287
mapped = []
288288
for mapping_keys, input_keys in mappings.items():
@@ -321,12 +321,12 @@ def load_csv(mapping, location):
321321
results = []
322322
with codecs.open(location, mode='rb', encoding='utf-8', errors='ignore') as csvfile:
323323
for row in OrderedDictReader(csvfile):
324-
input_row = {}
325-
# convert all the column keys to lower case as the same behavior as
326-
# when user use the --mapping
327-
for key in row.keys():
328-
input_row[key.lower()] = row[key]
329-
results.append(input_row)
324+
# convert all the column keys to lower case as the same
325+
# behavior as when user use the --mapping
326+
updated_row = OrderedDict(
327+
[(key.lower(), value) for key, value in row.items()]
328+
)
329+
results.append(updated_row)
330330
# user has the mapping option set
331331
if mapping:
332332
results = apply_mappings(results)

tests/test_model.py

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from __future__ import unicode_literals
2020

2121
from collections import OrderedDict
22+
import json
2223
import posixpath
2324
import unittest
2425
from unittest.case import expectedFailure
@@ -41,6 +42,27 @@
4142
from attributecode.util import load_csv
4243

4344

45+
def check_csvs(expected, result):
46+
"""
47+
Assert that the contents of two CSV files are equal.
48+
"""
49+
mapping = None
50+
expected = sorted([d.items() for d in load_csv(mapping, expected)])
51+
result = sorted([d.items() for d in load_csv(mapping, result)])
52+
assert expected == result
53+
54+
55+
def check_json(expected, result):
56+
"""
57+
Assert that the contents of two JSON files are equal.
58+
"""
59+
with open(expected) as e:
60+
expected = json.load(e, object_pairs_hook=OrderedDict)
61+
with open(result) as r:
62+
result = json.load(r, object_pairs_hook=OrderedDict)
63+
assert expected == result
64+
65+
4466
class FieldTest(unittest.TestCase):
4567
def test_Field_init(self):
4668
model.Field()
@@ -1016,19 +1038,6 @@ def test_load_dict_handles_field_validation_correctly(self):
10161038
with_empty=True)
10171039
assert test == dict(as_dict)
10181040

1019-
def check_csvs(self, expected, result):
1020-
"""
1021-
Assert that the content of two CSV file locations are equal.
1022-
"""
1023-
mapping = None
1024-
expected = [d.items() for d in load_csv(mapping, expected)]
1025-
result = [d.items() for d in load_csv(mapping, result)]
1026-
for ie, expect in enumerate(expected):
1027-
res = result[ie]
1028-
for ii, exp in enumerate(expect):
1029-
r = res[ii]
1030-
assert exp == r
1031-
10321041
def test_write_output_csv(self):
10331042
path = 'load/this.ABOUT'
10341043
test_file = get_test_loc(path)
@@ -1038,7 +1047,7 @@ def test_write_output_csv(self):
10381047
model.write_output([a], tmp_file, format='csv')
10391048

10401049
expected = get_test_loc('load/expected.csv')
1041-
self.check_csvs(expected, tmp_file)
1050+
check_csvs(expected, tmp_file)
10421051

10431052
def test_write_output_json(self):
10441053
path = 'load/this.ABOUT'
@@ -1049,7 +1058,8 @@ def test_write_output_json(self):
10491058
model.write_output([a], tmp_file, format='json')
10501059

10511060
expected = get_test_loc('load/expected.json')
1052-
self.check_csvs(expected, tmp_file)
1061+
check_json(expected, tmp_file)
1062+
10531063

10541064
class CollectorTest(unittest.TestCase):
10551065

tests/test_util.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from collections import OrderedDict
2222
import string
2323
import unittest
24+
from unittest.case import expectedFailure
2425

2526
from testing_utils import extract_test_loc
2627
from testing_utils import get_test_loc
@@ -304,7 +305,8 @@ def test_get_about_file_path_from_json(self):
304305

305306
# The column names should be converted to lowercase as the same behavior as
306307
# when user use the mapping.config
307-
"""def test_load_csv_does_not_convert_column_names_to_lowercase(self):
308+
@expectedFailure
309+
def test_load_csv_does_not_convert_column_names_to_lowercase(self):
308310
mapping = None
309311
test_file = get_test_loc('util/about_key_with_upper_case.csv')
310312
expected = [OrderedDict(
@@ -314,7 +316,7 @@ def test_get_about_file_path_from_json(self):
314316
('Version', '0.8.1')])
315317
]
316318
result = util.load_csv(mapping, test_file)
317-
assert expected == result"""
319+
assert expected == result
318320

319321
def test_get_locations_with_very_long_path(self):
320322
longpath = (

thirdparty/prod/PSF.LICENSE

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
2+
--------------------------------------------
3+
4+
1. This LICENSE AGREEMENT is between the Python Software Foundation
5+
("PSF"), and the Individual or Organization ("Licensee") accessing and
6+
otherwise using this software ("Python") in source or binary form and
7+
its associated documentation.
8+
9+
2. Subject to the terms and conditions of this License Agreement, PSF hereby
10+
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
11+
analyze, test, perform and/or display publicly, prepare derivative works,
12+
distribute, and otherwise use Python alone or in any derivative version,
13+
provided, however, that PSF's License Agreement and PSF's notice of copyright,
14+
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
15+
2011, 2012, 2013, 2014, 2015, 2016, 2017 Python Software Foundation; All Rights
16+
Reserved" are retained in Python alone or in any derivative version prepared by
17+
Licensee.
18+
19+
3. In the event Licensee prepares a derivative work that is based on
20+
or incorporates Python or any part thereof, and wants to make
21+
the derivative work available to others as provided herein, then
22+
Licensee hereby agrees to include in any such work a brief summary of
23+
the changes made to Python.
24+
25+
4. PSF is making Python available to Licensee on an "AS IS"
26+
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
27+
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
28+
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
29+
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
30+
INFRINGE ANY THIRD PARTY RIGHTS.
31+
32+
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
33+
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
34+
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
35+
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
36+
37+
6. This License Agreement will automatically terminate upon a material
38+
breach of its terms and conditions.
39+
40+
7. Nothing in this License Agreement shall be deemed to create any
41+
relationship of agency, partnership, or joint venture between PSF and
42+
Licensee. This License Agreement does not grant permission to use PSF
43+
trademarks or trade name in a trademark sense to endorse or promote
44+
products or services of Licensee, or any third party.
45+
46+
8. By copying, installing or otherwise using Python, Licensee
47+
agrees to be bound by the terms and conditions of this License
48+
Agreement.
12.9 KB
Binary file not shown.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
about_resource: backports.csv-1.0.5-py2.py3-none-any.whl
2+
version: 1.0.5
3+
download_url: https://pypi.python.org/packages/23/01/0b1fce3fd8199fe32338dc66747baad52c7183b7f587128bc77cefde0620/backports.csv-1.0.5-py2.py3-none-any.whl#md5=2b3dc8b5ca0a6f50ed50595a074ed870
4+
5+
name: backports.csv
6+
homepage: https://github.com/ryanhiebert/backports.csv
7+
owner: Ryan Hiebert
8+
9+
license: python
10+
license_file: PSF.LICENSE
11+
12+
vcs_tool: git
13+
vcs_repository: https://github.com/ryanhiebert/backports.csv.git

0 commit comments

Comments
 (0)