0001-add-python3-compatibility-29418.patch
setup.py | ||
---|---|---|
9 | 9 | |
10 | 10 |
class eo_sdist(sdist): |
11 | 11 |
def run(self): |
12 |
print "creating VERSION file"
|
|
12 |
print("creating VERSION file")
|
|
13 | 13 |
if os.path.exists('VERSION'): |
14 | 14 |
os.remove('VERSION') |
15 | 15 |
version = get_version() |
... | ... | |
17 | 17 |
version_file.write(version) |
18 | 18 |
version_file.close() |
19 | 19 |
sdist.run(self) |
20 |
print "removing VERSION file"
|
|
20 |
print("removing VERSION file")
|
|
21 | 21 |
if os.path.exists('VERSION'): |
22 | 22 |
os.remove('VERSION') |
23 | 23 | |
... | ... | |
38 | 38 |
else: |
39 | 39 |
result = '0.0.0-%s' % len(subprocess.check_output( |
40 | 40 |
['git', 'rev-list', 'HEAD']).splitlines()) |
41 |
return result.replace('-', '.').replace('.g', '+g') |
|
41 |
return result.decode('utf-8').replace('-', '.').replace('.g', '+g')
|
|
42 | 42 |
return '0.0.0' |
43 | 43 | |
44 | 44 |
src/ldaptools/ldap_source.py | ||
---|---|---|
25 | 25 |
continue |
26 | 26 |
entry = idict(entry) |
27 | 27 |
if 'objectclass' in entry: |
28 |
entry['objectclass'] = [istr(v) for v in entry['objectclass']] |
|
28 |
entry['objectclass'] = [istr(v.decode('utf-8')) for v in entry['objectclass']]
|
|
29 | 29 |
yield dn, entry |
30 | 30 | |
31 | 31 |
def __iter__(self): |
src/ldaptools/ldapsync/cmd.py | ||
---|---|---|
1 |
from __future__ import print_function |
|
2 | ||
1 | 3 |
import argparse |
2 | 4 |
import sys |
3 | 5 | |
... | ... | |
18 | 20 |
def f(value): |
19 | 21 |
try: |
20 | 22 |
return f1(value) |
21 |
except argparse.ArgumentTypeError, e1:
|
|
23 |
except argparse.ArgumentTypeError as e1:
|
|
22 | 24 |
try: |
23 | 25 |
return f2(value) |
24 |
except argparse.ArgumentTypeError, e2:
|
|
26 |
except argparse.ArgumentTypeError as e2:
|
|
25 | 27 |
raise argparse.ArgumentTypeError('%s and %s' % (e1.args[0], e2.args[0])) |
26 | 28 |
return f |
27 | 29 | |
28 | 30 | |
29 | 31 |
def object_class_pivot(value): |
30 |
value = filter(None, map(str.strip, map(str.lower, value.split())))
|
|
32 |
value = list(filter(None, map(str.strip, map(str.lower, value.split()))))
|
|
31 | 33 |
if len(value) != 2: |
32 | 34 |
raise argparse.ArgumentTypeError('%r is not a pair of an objectClass and an attribute name') |
33 | 35 |
return value |
... | ... | |
100 | 102 |
attributes = list(attributes) |
101 | 103 |
if not attributes: |
102 | 104 |
parser.print_help() |
103 |
print 'Yout must give at least one attribute to synchronize'
|
|
105 |
print('You must give at least one attribute to synchronize')
|
|
104 | 106 | |
105 | 107 |
if options.verbose: |
106 |
print 'Synchronizing ',
|
|
108 |
print('Synchronizing', end=' ')
|
|
107 | 109 |
if hasattr(options.source_uri, 'read'): |
108 | 110 |
if options.verbose: |
109 |
print options.source_uri.name,
|
|
111 |
print(options.source_uri.name, end=' ')
|
|
110 | 112 |
source = ldif_utils.ListLDIFParser(options.source_uri) |
111 | 113 |
source.parse() |
112 | 114 |
else: |
113 | 115 |
if options.verbose: |
114 |
print options.source_uri,
|
|
116 |
print(options.source_uri, end=' ')
|
|
115 | 117 |
conn = paged.PagedLDAPObject(options.source_uri) |
116 | 118 |
if options.source_uri.startswith('ldapi://'): |
117 | 119 |
conn.sasl_interactive_bind_s("", ldap.sasl.external()) |
... | ... | |
122 | 124 |
filterstr=options.source_filter) |
123 | 125 | |
124 | 126 |
if options.verbose: |
125 |
print 'to', options.target_uri
|
|
127 |
print('to', options.target_uri, end=' ')
|
|
126 | 128 |
target_conn = paged.PagedLDAPObject(options.target_uri) |
127 | 129 |
if options.target_uri.startswith('ldapi://'): |
128 | 130 |
target_conn.sasl_interactive_bind_s("", ldap.sasl.external()) |
... | ... | |
142 | 144 |
synchronize.build_actions() |
143 | 145 |
if options.verbose: |
144 | 146 |
for action in synchronize.actions: |
145 |
print ' -', action
|
|
147 |
print(' -', action)
|
|
146 | 148 |
if not synchronize.actions: |
147 |
print 'Nothing to do.'
|
|
149 |
print('Nothing to do.')
|
|
148 | 150 |
if not options.fake: |
149 | 151 |
synchronize.apply_actions() |
150 | 152 |
failed_actions = [action for action in synchronize.actions if action.errors] |
151 | 153 |
if failed_actions: |
152 |
print >>sys.stderr, 'Some actions failed:'
|
|
154 |
print('Some actions failed:', file=sys.stderr)
|
|
153 | 155 |
for action in failed_actions: |
154 |
print ' -', action
|
|
156 |
print(' -', action)
|
|
155 | 157 |
for error in action.errors: |
156 |
print ' *', error
|
|
158 |
print(' *', error)
|
|
157 | 159 |
raise SystemExit(1) |
src/ldaptools/ldif_utils.py | ||
---|---|---|
2 | 2 |
import ldif |
3 | 3 |
from ldap.dn import dn2str |
4 | 4 | |
5 |
from ldaptools.utils import idict, str2dn |
|
6 | ||
5 |
from ldaptools.utils import idict, str2dn, bytes2str_entry, str2bytes_entry |
|
7 | 6 | |
8 | 7 |
class AddError(Exception): |
9 | 8 |
pass |
... | ... | |
18 | 17 |
dn = str2dn(dn) |
19 | 18 |
dn = [[(part[0].lower(),) + part[1:] for part in rdn] for rdn in dn] |
20 | 19 |
dn = dn2str(dn) |
21 |
self.entries.append((dn, entry))
|
|
20 |
self.entries.append((dn, bytes2str_entry(entry)))
|
|
22 | 21 | |
23 | 22 |
def add(self, conn): |
24 | 23 |
for dn, entry in self.entries: |
25 | 24 |
try: |
26 |
conn.add_s(dn, ldap.modlist.addModlist(entry))
|
|
27 |
except Exception, e:
|
|
25 |
conn.add_s(dn, ldap.modlist.addModlist(str2bytes_entry(entry)))
|
|
26 |
except Exception as e:
|
|
28 | 27 |
raise AddError('error when adding %s' % dn, e) |
29 | 28 | |
30 | 29 |
def __iter__(self): |
src/ldaptools/slapd.py | ||
---|---|---|
1 |
import codecs |
|
1 | 2 |
import time |
2 | 3 |
import tempfile |
3 | 4 |
import shutil |
... | ... | |
6 | 7 |
import ldap |
7 | 8 |
import ldap.modlist |
8 | 9 |
import ldap.sasl |
9 |
import StringIO |
|
10 |
try: |
|
11 |
from StringIO import StringIO |
|
12 |
except ImportError: |
|
13 |
from io import StringIO |
|
10 | 14 |
import atexit |
11 | 15 | |
12 | 16 |
from ldaptools.ldif_utils import ListLDIFParser |
... | ... | |
87 | 91 |
process = None |
88 | 92 |
schemas = ['core', 'cosine', 'inetorgperson', 'nis', 'eduorg-200210-openldap', 'eduperson', |
89 | 93 |
'supann-2009'] |
90 |
schemas_ldif = [open(os.path.join(os.path.dirname(__file__), |
|
91 |
'schemas', '%s.ldif' % schema)).read() for schema in schemas] |
|
94 |
schemas_ldif = [codecs.open(os.path.join(os.path.dirname(__file__), |
|
95 |
'schemas', '%s.ldif' % schema), |
|
96 |
encoding='utf-8').read() for schema in schemas] |
|
92 | 97 |
checkpoints = None |
93 | 98 |
data_dirs = None |
94 | 99 |
db_index = 1 |
... | ... | |
172 | 177 |
if context: |
173 | 178 |
ldif = ldif.format(**context) |
174 | 179 |
slapadd = self.create_process([SLAPADD_PATH, '-v', '-n%d' % db, '-F', self.config_dir]) |
175 |
stdout, stderr = slapadd.communicate(input=ldif)
|
|
180 |
stdout, stderr = slapadd.communicate(input=bytearray(ldif, 'utf-8'))
|
|
176 | 181 |
assert slapadd.returncode == 0, 'slapadd failed: %s' % stderr |
177 | 182 | |
178 | 183 |
def start(self): |
... | ... | |
266 | 271 | |
267 | 272 |
if context: |
268 | 273 |
ldif = ldif.format(**context) |
269 |
parser = ListLDIFParser(StringIO.StringIO(ldif))
|
|
274 |
parser = ListLDIFParser(StringIO(ldif)) |
|
270 | 275 |
parser.parse() |
271 | 276 |
conn = self.get_connection_admin() |
272 | 277 |
parser.add(conn) |
src/ldaptools/synchronize.py | ||
---|---|---|
8 | 8 |
import ldap.dn |
9 | 9 | |
10 | 10 | |
11 |
from .utils import batch_generator, to_dict_of_set, idict, str2dn, istr |
|
11 |
from .utils import batch_generator, to_dict_of_set, idict, str2dn, istr, \ |
|
12 |
bytes2str_entry, str2bytes_entry |
|
12 | 13 | |
13 | 14 | |
14 | 15 |
@functools.total_ordering |
... | ... | |
48 | 49 |
for msgid in self.msgids: |
49 | 50 |
try: |
50 | 51 |
self.results.append(conn.result2(msgid)) |
51 |
except ldap.LDAPError, e:
|
|
52 |
except ldap.LDAPError as e:
|
|
52 | 53 |
self.errors.append(e) |
53 | 54 | |
54 | 55 |
def __str__(self): |
... | ... | |
62 | 63 |
order = 3 |
63 | 64 | |
64 | 65 |
def do(self, conn): |
65 |
self.msgids.append(conn.add(self.dn, ldap.modlist.addModlist(self.entry)))
|
|
66 |
self.msgids.append(conn.add(self.dn, ldap.modlist.addModlist(str2bytes_entry(self.entry))))
|
|
66 | 67 | |
67 | 68 | |
68 | 69 |
class Rename(Action): |
... | ... | |
83 | 84 | |
84 | 85 |
def do(self, conn): |
85 | 86 |
modlist = [] |
86 |
for key, values in self.entry.iteritems():
|
|
87 |
for key, values in str2bytes_entry(self.entry).items():
|
|
87 | 88 |
modlist.append((ldap.MOD_REPLACE, key, values)) |
88 | 89 |
self.msgids.append(conn.modify(self.dn, modlist)) |
89 | 90 | |
... | ... | |
144 | 145 |
def get_pivot_attribute(self, dn, entry): |
145 | 146 |
'''Find a pivot attribute value for an LDAP entry''' |
146 | 147 |
for objc, attr in self.pivot_attributes: |
147 |
entry['objectclass'] = map(istr, entry['objectclass']) |
|
148 |
if objc in entry['objectclass']: |
|
148 |
if istr(objc) in [istr(oc.decode('utf-8')) |
|
149 |
if isinstance(oc, bytes) else oc |
|
150 |
for oc in entry['objectclass']]: |
|
149 | 151 |
try: |
150 | 152 |
value = entry[attr] |
151 | 153 |
except KeyError: |
152 | 154 |
raise Exception('entry %s missing pivot attribute %s: %s' % (dn, attr, entry)) |
153 | 155 |
break |
154 | 156 |
else: |
155 |
raise Exception('entry %s has unknown objectclasses %s' % (dn, entry['objectclass'])) |
|
157 |
raise Exception('entry %s has unknown objectclasses %s' % (dn, |
|
158 |
[objclass for objclass in entry['objectclass']])) |
|
156 | 159 |
if len(value) != 1: |
157 | 160 |
raise Exception('entry %s pivot attribute %s must have only one value' % (dn, attr)) |
161 |
value = value[0] |
|
162 |
""" |
|
163 |
may be used for input entries or output entries. |
|
164 |
decoding may be required |
|
165 |
""" |
|
166 |
if isinstance(value, bytes): |
|
167 |
value = value.decode('utf-8') |
|
158 | 168 |
if attr in self.case_insensitive_attribute: |
159 |
value = map(istr, value)
|
|
160 |
return objc, attr, value[0]
|
|
169 |
value = istr(value)
|
|
170 |
return objc, attr, value |
|
161 | 171 | |
162 | 172 |
def get_target_entries(self, filterstr=None, attributes=[]): |
163 | 173 |
'''Return all target entries''' |
164 | 174 |
try: |
165 | 175 |
# Check base DN exist |
166 | 176 |
self.target_conn.search_s(self.target_dn, ldap.SCOPE_BASE) |
167 |
l = self.target_conn.paged_search_ext_s(self.target_dn, ldap.SCOPE_SUBTREE,
|
|
177 |
res = self.target_conn.paged_search_ext_s(self.target_dn, ldap.SCOPE_SUBTREE,
|
|
168 | 178 |
filterstr=filterstr or self.all_filter, |
169 | 179 |
attrlist=attributes) |
170 |
return ((dn, idict(entry)) for dn, entry in l if dn)
|
|
180 |
return ((dn, idict(bytes2str_entry(entry))) for dn, entry in res if dn)
|
|
171 | 181 |
except ldap.NO_SUCH_OBJECT: |
172 | 182 |
return [] |
173 | 183 | |
... | ... | |
215 | 225 |
seen_dn.add(out_dn) |
216 | 226 |
self.rename(new_out_dn, target_dn) |
217 | 227 |
renamed_dn[str2dn(new_out_dn)] = str2dn(target_dn) |
218 |
if to_dict_of_set(out_entry) != to_dict_of_set(entry):
|
|
228 |
if to_dict_of_set(out_entry) != to_dict_of_set(bytes2str_entry(entry)):
|
|
219 | 229 |
new_entry = {} |
220 | 230 |
for attribute in self.attributes: |
221 | 231 |
if attribute in to_dict_of_set(entry): |
... | ... | |
233 | 243 |
self.actions = [] |
234 | 244 |
# Order source entries by DN depth |
235 | 245 |
entries = list(self.source) |
236 |
entries.sort(key=lambda (dn, entry): len(str2dn(dn)))
|
|
246 |
entries.sort(key=lambda dn_entry: len(str2dn(dn_entry[0])))
|
|
237 | 247 |
for dn, entry in entries: |
238 | 248 |
for key in entry.keys(): |
239 |
if not key in self.attributes:
|
|
249 |
if not str(key.lower()) in self.attributes:
|
|
240 | 250 |
del entry[key] |
241 | 251 |
# First create, rename and update |
242 | 252 |
for batch in batch_generator(entries, self.BATCH_SIZE): |
src/ldaptools/utils.py | ||
---|---|---|
1 | 1 |
import ldap.dn |
2 |
from six import string_types |
|
2 | 3 | |
3 | 4 | |
4 | 5 |
# Copied from http://code.activestate.com/recipes/194371-case-insensitive-strings/ |
... | ... | |
7 | 8 |
Performs like str except comparisons are case insensitive.""" |
8 | 9 | |
9 | 10 |
def __init__(self, strMe): |
10 |
str.__init__(self, strMe)
|
|
11 |
super(str, self).__init__()
|
|
11 | 12 |
self.__lowerCaseMe = strMe.lower() |
12 | 13 | |
13 | 14 |
def __repr__(self): |
... | ... | |
80 | 81 |
def findkey(self, item): |
81 | 82 |
"""A caseless way of checking if a key exists or not. |
82 | 83 |
It returns None or the correct key.""" |
83 |
if not isinstance(item, str): |
|
84 |
if not isinstance(item, string_types):
|
|
84 | 85 |
raise TypeError('Keywords for this object must be strings. You supplied %s' % type(item)) |
85 | 86 |
key = item.lower() |
86 | 87 |
try: |
... | ... | |
147 | 148 | |
148 | 149 |
def has_key(self, item): |
149 | 150 |
"""A case insensitive test for keys.""" |
150 |
if not isinstance(item, str): |
|
151 |
if not isinstance(item, string_types):
|
|
151 | 152 |
return False # should never have a non-string key |
152 | 153 |
return item.lower() in self._keydict # does the key exist |
153 | 154 | |
154 | 155 |
def __contains__(self, item): |
155 | 156 |
"""A case insensitive __contains__.""" |
156 |
if not isinstance(item, str): |
|
157 |
if not isinstance(item, string_types):
|
|
157 | 158 |
return False # should never have a non-string key |
158 | 159 |
return item.lower() in self._keydict # does the key exist |
159 | 160 | |
... | ... | |
212 | 213 |
return True |
213 | 214 | |
214 | 215 |
def __ne__(self, other): |
215 |
return not (self == other)
|
|
216 |
return not (self == other)
|
|
216 | 217 | |
217 | 218 | |
218 | 219 |
def batch_generator(gen, *batch_size): |
... | ... | |
229 | 230 | |
230 | 231 | |
231 | 232 |
def to_dict_of_set(d): |
232 |
r = idict({k: set(v) for k, v in d.iteritems()})
|
|
233 |
r = idict({k: set(v) for k, v in d.items()}) |
|
233 | 234 |
if 'objectclass' in r: |
234 | 235 |
r['objectclass'] = set(istr(v) for v in r['objectclass']) |
235 | 236 |
return r |
... | ... | |
237 | 238 | |
238 | 239 |
def str2dn(s): |
239 | 240 |
return tuple(map(tuple, ldap.dn.str2dn(s))) |
241 | ||
242 | ||
243 |
def bytes2str_entry(entry): |
|
244 |
str_entry = {} |
|
245 |
for key, values in entry.items(): |
|
246 |
str_entry[key] = [v.decode('utf-8') if isinstance(v, bytes) else v for v in values] |
|
247 |
return str_entry |
|
248 | ||
249 |
def str2bytes_entry(entry): |
|
250 |
bytes_entry = {} |
|
251 | ||
252 |
# python2 backward compat |
|
253 |
try: |
|
254 |
tested_types = basestring |
|
255 |
except NameError: |
|
256 |
tested_types = str |
|
257 | ||
258 |
for key, values in entry.items(): |
|
259 |
bytes_entry[key] = [v.encode('utf-8') if isinstance(v, tested_types) else v for v in values] |
|
260 |
return bytes_entry |
tests/conftest.py | ||
---|---|---|
1 |
from __future__ import print_function |
|
2 | ||
1 | 3 |
import pytest |
2 | 4 |
import tempfile |
3 | 5 |
import os |
... | ... | |
98 | 100 |
handle, path = tempfile.mkstemp() |
99 | 101 |
with open(path, 'w') as f: |
100 | 102 |
for attribute in attributes: |
101 |
print >>f, ' %s ' % attribute
|
|
103 |
print(' %s ' % attribute, file=f)
|
|
102 | 104 |
f.flush() |
103 | 105 |
def finalize(): |
104 | 106 |
os.unlink(path) |
tests/test_ldif_utils.py | ||
---|---|---|
1 |
import StringIO |
|
1 |
try: |
|
2 |
from StringIO import StringIO |
|
3 |
except ImportError: |
|
4 |
from io import StringIO |
|
2 | 5 | |
3 | 6 |
from ldaptools.ldif_utils import ListLDIFParser |
4 | 7 | |
5 | 8 | |
6 | 9 |
def test_ldifparser(): |
7 |
parser = ListLDIFParser(StringIO.StringIO('''dn: o=orga
|
|
10 |
parser = ListLDIFParser(StringIO('''dn: o=orga |
|
8 | 11 |
objectClass: organization |
9 | 12 | |
10 | 13 |
''')) |
tests/test_synchronize.py | ||
---|---|---|
1 |
import StringIO |
|
1 |
try: |
|
2 |
from StringIO import StringIO |
|
3 |
except ImportError: |
|
4 |
from io import StringIO |
|
2 | 5 | |
3 | 6 |
import ldap |
4 | 7 | |
... | ... | |
17 | 20 |
conn = slapd.get_connection_admin() |
18 | 21 | |
19 | 22 |
def syn_ldif(ldif): |
20 |
parser = ListLDIFParser(StringIO.StringIO(ldif))
|
|
23 |
parser = ListLDIFParser(StringIO(ldif)) |
|
21 | 24 |
parser.parse() |
22 | 25 |
synchronize = Synchronize(parser, 'o=orga', conn, 'o=orga', |
23 | 26 |
pivot_attributes=pivot_attributes, |
... | ... | |
163 | 166 |
conn = slapd.get_connection_admin() |
164 | 167 | |
165 | 168 |
def syn_ldif(ldif): |
166 |
parser = ListLDIFParser(StringIO.StringIO(ldif))
|
|
169 |
parser = ListLDIFParser(StringIO(ldif)) |
|
167 | 170 |
parser.parse() |
168 | 171 |
synchronize = Synchronize(parser, 'o=orga', conn, 'o=orga', |
169 | 172 |
pivot_attributes=pivot_attributes, |
tox.ini | ||
---|---|---|
5 | 5 | |
6 | 6 |
[tox] |
7 | 7 |
toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/ldaptools/ |
8 |
envlist = coverage,package
|
|
8 |
envlist = py2-coverage-ldap2,py{2,3}-coverage-ldap3,package
|
|
9 | 9 | |
10 | 10 |
[testenv] |
11 | 11 |
usedevelop = true |
... | ... | |
16 | 16 |
pytest |
17 | 17 |
pytest-cov |
18 | 18 |
pytest-random |
19 |
python-ldap<3 |
|
19 |
ldap3: python-ldap>2 |
|
20 |
ldap2: python-ldap<3 |
|
20 | 21 |
commands = |
21 | 22 |
py.test {env:COVERAGE:} {posargs:--random tests} |
22 | 23 | |
23 |
- |