Skip to content

Commit 5d5a037

Browse files
committed
[MIG] Migration to python 3 while keeping compatibility with python 2
[IMP] possibility to use file object or similar instead of file name for tranform, load and extract operation [TEST] Launch test with python 2 and python 3 + generate coverage report [MIG] migration odoo-client-lib a fork of openerp-client-lib that is now compatible with python 3 [IMP] change requirements and setu.py
1 parent 35ebf93 commit 5d5a037

23 files changed

+220
-168
lines changed

odoo_csv_tools/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
import lib
2-
import export_threaded
3-
import import_threaded
1+
from . import lib
2+
from . import export_threaded
3+
from . import import_threaded

odoo_csv_tools/export_threaded.py

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,25 @@
1414
You should have received a copy of the GNU Lesser General Public License
1515
along with this program. If not, see <http://www.gnu.org/licenses/>.
1616
'''
17-
18-
from xmlrpclib import Fault
19-
from time import time
20-
from itertools import islice, chain
21-
22-
2317
import sys
2418
import csv
2519

26-
from lib import conf_lib
27-
from lib.conf_lib import log_error, log_info
28-
from lib.internal.rpc_thread import RpcThread
29-
from lib.internal.csv_reader import UnicodeWriter
30-
from odoo_csv_tools.lib.internal.io import ListWriter
20+
from time import time
3121

32-
csv.field_size_limit(sys.maxint)
22+
from . lib import conf_lib
23+
from . lib.conf_lib import log_error, log_info
24+
from . lib.internal.rpc_thread import RpcThread
25+
from . lib.internal.csv_reader import UnicodeWriter
26+
from . lib.internal.io import ListWriter, open_write
27+
from . lib.internal.tools import batch
3328

29+
if sys.version_info >= (3, 0, 0):
30+
from xmlrpc.client import Fault
31+
csv.field_size_limit(sys.maxsize)
32+
else:
33+
from xmlrpclib import Fault
34+
csv.field_size_limit(sys.maxint)
3435

35-
def batch(iterable, size):
36-
sourceiter = iter(iterable)
37-
while True:
38-
batchiter = islice(sourceiter, size)
39-
yield chain([batchiter.next()], batchiter)
4036

4137
class RPCThreadExport(RpcThread):
4238

@@ -80,7 +76,7 @@ def export_data(config_file, model, domain, header, context=None, output=None, m
8076
object_registry = conf_lib.get_server_connection(config_file).get_model(model)
8177

8278
if output:
83-
file_result = open(output, "wb")
79+
file_result = open_write(output)
8480
writer = UnicodeWriter(file_result, delimiter=separator, encoding=encoding, quoting=csv.QUOTE_ALL)
8581
else:
8682
writer = ListWriter()
@@ -104,6 +100,3 @@ def export_data(config_file, model, domain, header, context=None, output=None, m
104100
return False, False
105101
else:
106102
return writer.header, writer.data
107-
108-
109-

odoo_csv_tools/import_threaded.py

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,22 @@
2020
import csv
2121

2222
from time import time
23-
from itertools import islice, chain
24-
from xmlrpclib import Fault
2523

26-
from lib import conf_lib
27-
from lib.conf_lib import log_error, log_info, log
28-
from lib.internal.rpc_thread import RpcThread
29-
from lib.internal.io import ListWriter
30-
from lib.internal.csv_reader import UnicodeReader, UnicodeWriter
24+
from . lib import conf_lib
25+
from . lib.conf_lib import log_error, log_info, log
26+
from . lib.internal.rpc_thread import RpcThread
27+
from . lib.internal.io import ListWriter, open_read, open_write
28+
from . lib.internal.csv_reader import UnicodeReader, UnicodeWriter
29+
from . lib.internal.tools import batch
30+
31+
if sys.version_info >= (3, 0, 0):
32+
from xmlrpc.client import Fault
33+
else:
34+
from xmlrpclib import Fault
35+
from builtins import range
3136

32-
csv.field_size_limit(sys.maxint)
3337

3438

35-
def batch(iterable, size):
36-
sourceiter = iter(iterable)
37-
while True:
38-
batchiter = islice(sourceiter, size)
39-
yield chain([batchiter.next()], batchiter)
4039

4140
class RPCThreadImport(RpcThread):
4241

@@ -141,13 +140,13 @@ def check_id_column(header):
141140

142141
def skip_line(reader):
143142
log_info("Skipping until line %s excluded" % skip)
144-
for _ in xrange(1, skip):
143+
for _ in range(1, skip):
145144
reader.next()
146145

147146
log('open %s' % file_to_read)
148-
file_ref = open(file_to_read, 'r')
147+
file_ref = open_read(file_to_read, encoding='utf-8-sig')
149148
reader = UnicodeReader(file_ref, delimiter=delimiter, encoding='utf-8-sig')
150-
header = reader.next()
149+
header = next(reader)
151150
header = get_real_header(header)
152151
check_id_column(header)
153152
skip_line(reader)
@@ -176,7 +175,7 @@ def import_data(config_file, model, header=None, data=None, file_csv=None, conte
176175
if file_csv:
177176
header, data = read_file(file_csv, delimiter=separator, encoding=encoding, skip=skip)
178177
fail_file = fail_file or file_csv + ".fail"
179-
file_result = open(fail_file, "wb")
178+
file_result = open_write(fail_file, encoding=encoding)
180179

181180
if not header or data == None:
182181
raise ValueError("Please provide either a data file or a header and data")
@@ -220,4 +219,3 @@ def import_data(config_file, model, header=None, data=None, file_csv=None, conte
220219
return False, False
221220
else:
222221
return writer.header, writer.data
223-

odoo_csv_tools/lib/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import internal
2-
import conf_lib
3-
import workflow
4-
import checker
5-
import mapper
6-
import transform
1+
from . import internal
2+
from . import conf_lib
3+
from . import workflow
4+
from . import checker
5+
from . import mapper
6+
from . import transform

odoo_csv_tools/lib/checker.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def check_id_validity(header, data):
1515
line = [s.strip() if s.strip() not in null_values else '' for s in line]
1616
line_dict = dict(zip(header, line))
1717
if not regular.match(line_dict[id_field]):
18-
print "Check Failed Id Validity", i+1, line_dict[id_field]
18+
print("Check Failed Id Validity", i+1, line_dict[id_field])
1919
res = False
2020
return res
2121
return check_id_validity
@@ -27,15 +27,15 @@ def check_line_length(header, data):
2727
for line in data:
2828
i+=1
2929
if len(line) != length:
30-
print "Check Failed", i, "Line Length", len(line)
30+
print("Check Failed", i, "Line Length", len(line))
3131
res = False
3232
return res
3333
return check_line_length
3434

3535
def line_number_checker(line_number):
3636
def check_line_numner(header, data):
3737
if len(data) + 1 != line_number:
38-
print "Check Line Number Failed %s instead of %s" % (len(data) + 1, line_number)
38+
print("Check Line Number Failed %s instead of %s" % (len(data) + 1, line_number))
3939
return False
4040
else:
4141
return True
@@ -47,8 +47,8 @@ def check_max_cell_len(header, data):
4747
for i, line in enumerate(data):
4848
for ele in line:
4949
if len(ele) > max_cell_len:
50-
print "Check Failed", i + 1, "Cell Length", len(ele)
51-
print line
50+
print("Check Failed", i + 1, "Cell Length", len(ele))
51+
print(line)
5252
res = False
5353
return res
5454
return check_max_cell_len

odoo_csv_tools/lib/conf_lib.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
import openerplib
2-
import ConfigParser
1+
import odoolib
2+
import sys
3+
if sys.version_info >= (3, 0, 0):
4+
import configparser as ConfigParser
5+
else:
6+
import ConfigParser
37
import logging
48
import sys
59

@@ -15,7 +19,7 @@ def get_server_connection(config_file):
1519
protocol = config.get('Connection', 'protocol')
1620
port = int(config.get('Connection', 'port'))
1721
uid = int(config.get('Connection', 'uid'))
18-
return openerplib.get_connection(hostname=hostname, database=database, login=login, password=password, protocol=protocol, port=port, user_id=uid)
22+
return odoolib.get_connection(hostname=hostname, database=database, login=login, password=password, protocol=protocol, port=port, user_id=uid)
1923

2024
def init_logger():
2125
logger_err = logging.getLogger("error")
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import exceptions
2-
import tools
3-
import csv_reader
4-
import io
5-
import rpc_thread
1+
from . import exceptions
2+
from . import tools
3+
from . import csv_reader
4+
from . import io
5+
from . import rpc_thread

odoo_csv_tools/lib/internal/csv_reader.py

Lines changed: 17 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,32 @@
33
44
@author: openerp
55
'''
6-
import csv, codecs, cStringIO
6+
from __future__ import absolute_import
7+
import sys
8+
#import csv, codecs
9+
if sys.version_info >= (3, 0, 0):
10+
import csv
11+
else:
12+
import unicodecsv as csv
13+
from io import StringIO
714
import threading
815

9-
class UTF8Recoder:
10-
"""
11-
Iterator that reads an encoded stream and reencodes the input to UTF-8
12-
"""
13-
def __init__(self, f, encoding):
14-
self.reader = codecs.getreader(encoding)(f)
15-
16-
def __iter__(self):
17-
return self
18-
19-
def next(self):
20-
return self.reader.next().encode("utf-8")
21-
2216
class UnicodeReader:
2317
"""
2418
A CSV reader which will iterate over lines in the CSV file "f",
2519
which is encoded in the given encoding.
2620
"""
2721

2822
def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
29-
f = UTF8Recoder(f, encoding)
3023
self.reader = csv.reader(f, dialect=dialect, **kwds)
3124

3225
def next(self):
33-
row = self.reader.next()
34-
return [unicode(s, "utf-8") for s in row]
26+
#For python2
27+
return self.reader.next()
28+
29+
def __next__(self):
30+
#For python3
31+
return self.reader.__next__()
3532

3633
def __iter__(self):
3734
return self
@@ -45,29 +42,17 @@ class UnicodeWriter:
4542

4643
def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
4744
# Redirect output to a queue
48-
self.queue = cStringIO.StringIO()
49-
self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
5045
self.stream = f
51-
self.encoder = codecs.getincrementalencoder(encoding)()
46+
self.writer = writer = csv.writer(f, dialect=dialect, **kwds)
5247
self.lock = threading.RLock()
5348

5449
def writerow(self, row):
5550
self.lock.acquire()
56-
self.writer.writerow([str(s) if isinstance(s, bool) else s.encode("utf-8") for s in row])
57-
# Fetch UTF-8 output from the queue ...
58-
data = self.queue.getvalue()
59-
data = data.decode("utf-8")
60-
# ... and reencode it into the target encoding
61-
data = self.encoder.encode(data)
62-
# write to the target stream
63-
self.stream.write(data)
64-
# empty queue
65-
self.queue.truncate(0)
51+
self.writer.writerow(row)
6652
self.lock.release()
6753

6854
def writerows(self, rows):
6955
self.lock.acquire()
70-
for row in rows:
71-
self.writerow(row)
56+
self.writer.writerows(rows)
7257
self.stream.flush()
7358
self.lock.release()

odoo_csv_tools/lib/internal/exceptions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55
'''
66

77
class SkippingException(Exception):
8-
pass
8+
def __init__(self, message):
9+
self.message = message

odoo_csv_tools/lib/internal/io.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,40 @@
33
44
@author: mythrys
55
'''
6+
from __future__ import absolute_import
7+
68
import csv
79
import os
8-
9-
from csv_reader import UnicodeWriter, UnicodeReader
10-
10+
import sys
11+
from . csv_reader import UnicodeWriter, UnicodeReader
12+
13+
"""
14+
Compatibility layer between python 2.7 and python 3
15+
"""
16+
def is_string(f):
17+
if sys.version_info >= (3, 0, 0):
18+
return isinstance(f, str)
19+
else:
20+
return isinstance(f, basestring)
21+
22+
def open_read(f, encoding='utf-8-sig'):
23+
if not is_string(f):
24+
return f
25+
if sys.version_info >= (3, 0, 0):
26+
return open(f, 'r', newline='', encoding=encoding)
27+
else:
28+
return open(f, 'r')
29+
30+
def open_write(f, encoding='utf-8-sig'):
31+
if not is_string(f):
32+
return f
33+
if sys.version_info >= (3, 0, 0):
34+
return open(f, "w", newline='', encoding=encoding)
35+
else:
36+
return open(f, "w")
1137

1238
def write_csv(filename, header, data):
13-
file_result = open(filename, "wb")
39+
file_result = open_write(filename)
1440
c = UnicodeWriter(file_result, delimiter=';', quoting=csv.QUOTE_ALL)
1541
c.writerow(header)
1642
for d in data:

odoo_csv_tools/lib/internal/tools.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@
33
44
@author: Thibault Francois <[email protected]>
55
'''
6+
from itertools import islice, chain
67

8+
def batch(iterable, size):
9+
sourceiter = iter(iterable)
10+
while True:
11+
batchiter = islice(sourceiter, size)
12+
yield chain([next(batchiter)], batchiter)
713
"""
814
Data formatting tools
915
"""
1016
def to_xmlid(name):
11-
return name.replace('.', '_').replace(',', '_').strip()
17+
return name.replace('.', '_').replace(',', '_').replace('\n', '_').strip()
1218

1319
def list_to_xml_id(names):
1420
return '_'.join([to_xmlid(name) for name in names])
@@ -77,10 +83,10 @@ def add_line(self, line, header):
7783
def generate_line(self):
7884
lines_header = ['id', 'product_tmpl_id/id', 'attribute_id/id', 'value_ids/id']
7985
lines_out = []
80-
for template_id, attributes in self.data.iteritems():
86+
for template_id, attributes in self.data.items():
8187
if not template_id:
8288
continue
83-
for attribute, values in attributes.iteritems():
89+
for attribute, values in attributes.items():
8490
line = [self.id_gen(template_id, attributes), template_id, attribute, ','.join(values)]
8591
lines_out.append(line)
8692
return lines_header, lines_out

0 commit comments

Comments
 (0)