Merge from upstream CVS HEAD
This commit is contained in:
19
CHANGES
19
CHANGES
@@ -1,3 +1,20 @@
|
|||||||
|
----------------------------------------------------------------
|
||||||
|
Released 2.4.21 2015-07-xx
|
||||||
|
|
||||||
|
Changes since 2.4.20:
|
||||||
|
|
||||||
|
Lib/
|
||||||
|
* LDAPObject.read_s() now returns None instead of raising
|
||||||
|
ldap.NO_SUCH_OBJECT in case the search operation returned emtpy result.
|
||||||
|
* ldap.resiter.ResultProcessor.allresults() now takes new key-word
|
||||||
|
argument add_ctrls which is internally passed to LDAPObject.result4()
|
||||||
|
and lets the method also return response control along with the search
|
||||||
|
results.
|
||||||
|
* Added ldap.controls.deref implementing support for dereference control
|
||||||
|
|
||||||
|
Tests/
|
||||||
|
* Unit tests for module ldif (thanks to Petr Viktorin)
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
Released 2.4.20 2015-07-07
|
Released 2.4.20 2015-07-07
|
||||||
|
|
||||||
@@ -1178,4 +1195,4 @@ Released 2.0.0pre02 2002-02-01
|
|||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
Released 1.10alpha3 2000-09-19
|
Released 1.10alpha3 2000-09-19
|
||||||
|
|
||||||
$Id: CHANGES,v 1.350 2015/07/07 13:21:42 stroeder Exp $
|
$Id: CHANGES,v 1.355 2015/09/19 13:38:30 stroeder Exp $
|
||||||
|
|||||||
50
Demo/pyasn1/derefcontrol.py
Normal file
50
Demo/pyasn1/derefcontrol.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""
|
||||||
|
This sample script demonstrates the use of the dereference control
|
||||||
|
(see https://tools.ietf.org/html/draft-masarati-ldap-deref)
|
||||||
|
|
||||||
|
Requires module pyasn1 (see http://pyasn1.sourceforge.net/)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pprint,ldap,ldap.modlist,ldap.resiter
|
||||||
|
|
||||||
|
from ldap.controls.deref import DereferenceControl
|
||||||
|
|
||||||
|
uri = "ldap://ipa.demo1.freeipa.org"
|
||||||
|
|
||||||
|
class MyLDAPObject(ldap.ldapobject.LDAPObject,ldap.resiter.ResultProcessor):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
l = MyLDAPObject(uri,trace_level=0)
|
||||||
|
l.simple_bind_s('uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org','Secret123')
|
||||||
|
|
||||||
|
dc = DereferenceControl(
|
||||||
|
True,
|
||||||
|
{
|
||||||
|
'member':[
|
||||||
|
'uid',
|
||||||
|
'description',
|
||||||
|
'cn',
|
||||||
|
'mail',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
print 'pyasn1 output of request control:'
|
||||||
|
print dc._derefSpecs().prettyPrint()
|
||||||
|
|
||||||
|
msg_id = l.search_ext(
|
||||||
|
'dc=demo1,dc=freeipa,dc=org',
|
||||||
|
ldap.SCOPE_SUBTREE,
|
||||||
|
'(objectClass=groupOfNames)',
|
||||||
|
attrlist=['cn','objectClass','member','description'],
|
||||||
|
serverctrls = [dc]
|
||||||
|
)
|
||||||
|
|
||||||
|
for res_type,res_data,res_msgid,res_controls in l.allresults(msg_id,add_ctrls=1):
|
||||||
|
for dn,entry,deref_control in res_data:
|
||||||
|
# process dn and entry
|
||||||
|
print dn,entry['objectClass']
|
||||||
|
if deref_control:
|
||||||
|
pprint.pprint(deref_control[0].derefRes)
|
||||||
@@ -4,13 +4,13 @@ dsml - generate and parse DSMLv1 data
|
|||||||
|
|
||||||
See http://www.python-ldap.org/ for details.
|
See http://www.python-ldap.org/ for details.
|
||||||
|
|
||||||
$Id: dsml.py,v 1.37 2015/06/05 21:04:58 stroeder Exp $
|
$Id: dsml.py,v 1.38 2015/08/08 13:36:30 stroeder Exp $
|
||||||
|
|
||||||
Python compability note:
|
Python compability note:
|
||||||
Tested with Python 2.0+.
|
Tested with Python 2.0+.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = '2.4.20'
|
__version__ = '2.4.21'
|
||||||
|
|
||||||
import string,base64
|
import string,base64
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ ldap - base module
|
|||||||
|
|
||||||
See http://www.python-ldap.org/ for details.
|
See http://www.python-ldap.org/ for details.
|
||||||
|
|
||||||
$Id: __init__.py,v 1.97 2015/06/05 21:04:58 stroeder Exp $
|
$Id: __init__.py,v 1.98 2015/08/08 13:36:30 stroeder Exp $
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# This is also the overall release version number
|
# This is also the overall release version number
|
||||||
|
|
||||||
__version__ = '2.4.20'
|
__version__ = '2.4.21'
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|||||||
122
Lib/ldap/controls/deref.py
Normal file
122
Lib/ldap/controls/deref.py
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
ldap.controls.deref - classes for
|
||||||
|
(see https://tools.ietf.org/html/draft-masarati-ldap-deref)
|
||||||
|
|
||||||
|
See http://www.python-ldap.org/ for project details.
|
||||||
|
|
||||||
|
$Id: deref.py,v 1.2 2015/09/19 13:41:01 stroeder Exp $
|
||||||
|
"""
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'DEREF_CONTROL_OID',
|
||||||
|
'DereferenceControl',
|
||||||
|
]
|
||||||
|
|
||||||
|
import ldap.controls
|
||||||
|
from ldap.controls import LDAPControl,KNOWN_RESPONSE_CONTROLS
|
||||||
|
|
||||||
|
import pyasn1_modules.rfc2251
|
||||||
|
from pyasn1.type import namedtype,univ,tag
|
||||||
|
from pyasn1.codec.ber import encoder,decoder
|
||||||
|
from pyasn1_modules.rfc2251 import LDAPDN,AttributeDescription,AttributeDescriptionList,AttributeValue
|
||||||
|
|
||||||
|
|
||||||
|
DEREF_CONTROL_OID = '1.3.6.1.4.1.4203.666.5.16'
|
||||||
|
|
||||||
|
|
||||||
|
# Request types
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# For compability with ASN.1 declaration in I-D
|
||||||
|
AttributeList = AttributeDescriptionList
|
||||||
|
|
||||||
|
class DerefSpec(univ.Sequence):
|
||||||
|
componentType = namedtype.NamedTypes(
|
||||||
|
namedtype.NamedType(
|
||||||
|
'derefAttr',
|
||||||
|
AttributeDescription()
|
||||||
|
),
|
||||||
|
namedtype.NamedType(
|
||||||
|
'attributes',
|
||||||
|
AttributeList()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
class DerefSpecs(univ.SequenceOf):
|
||||||
|
componentType = DerefSpec()
|
||||||
|
|
||||||
|
# Response types
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
class AttributeValues(univ.SetOf):
|
||||||
|
componentType = AttributeValue()
|
||||||
|
|
||||||
|
|
||||||
|
class PartialAttribute(univ.Sequence):
|
||||||
|
componentType = namedtype.NamedTypes(
|
||||||
|
namedtype.NamedType('type', AttributeDescription()),
|
||||||
|
namedtype.NamedType('vals', AttributeValues()),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PartialAttributeList(univ.SequenceOf):
|
||||||
|
componentType = PartialAttribute()
|
||||||
|
tagSet = univ.Sequence.tagSet.tagImplicitly(
|
||||||
|
tag.Tag(tag.tagClassContext,tag.tagFormatConstructed,0)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DerefRes(univ.Sequence):
|
||||||
|
componentType = namedtype.NamedTypes(
|
||||||
|
namedtype.NamedType('derefAttr', AttributeDescription()),
|
||||||
|
namedtype.NamedType('derefVal', LDAPDN()),
|
||||||
|
namedtype.OptionalNamedType('attrVals', PartialAttributeList()),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DerefResultControlValue(univ.SequenceOf):
|
||||||
|
componentType = DerefRes()
|
||||||
|
|
||||||
|
|
||||||
|
class DereferenceControl(LDAPControl):
|
||||||
|
controlType = DEREF_CONTROL_OID
|
||||||
|
|
||||||
|
def __init__(self,criticality=False,derefSpecs=None):
|
||||||
|
LDAPControl.__init__(self,self.controlType,criticality)
|
||||||
|
self.derefSpecs = derefSpecs or {}
|
||||||
|
|
||||||
|
def _derefSpecs(self):
|
||||||
|
deref_specs = DerefSpecs()
|
||||||
|
i = 0
|
||||||
|
for deref_attr,deref_attribute_names in self.derefSpecs.items():
|
||||||
|
deref_spec = DerefSpec()
|
||||||
|
deref_attributes = AttributeList()
|
||||||
|
for j in range(len(deref_attribute_names)):
|
||||||
|
deref_attributes.setComponentByPosition(j,deref_attribute_names[j])
|
||||||
|
deref_spec.setComponentByName('derefAttr',AttributeDescription(deref_attr))
|
||||||
|
deref_spec.setComponentByName('attributes',deref_attributes)
|
||||||
|
deref_specs.setComponentByPosition(i,deref_spec)
|
||||||
|
i += 1
|
||||||
|
return deref_specs
|
||||||
|
|
||||||
|
def encodeControlValue(self):
|
||||||
|
return encoder.encode(self._derefSpecs())
|
||||||
|
|
||||||
|
def decodeControlValue(self,encodedControlValue):
|
||||||
|
decodedValue,_ = decoder.decode(encodedControlValue,asn1Spec=DerefResultControlValue())
|
||||||
|
self.derefRes = {}
|
||||||
|
for deref_res in decodedValue:
|
||||||
|
deref_attr,deref_val,deref_vals = deref_res
|
||||||
|
partial_attrs_dict = dict([
|
||||||
|
(str(t),map(str,v))
|
||||||
|
for t,v in deref_vals or []
|
||||||
|
])
|
||||||
|
try:
|
||||||
|
self.derefRes[str(deref_attr)].append((str(deref_val),partial_attrs_dict))
|
||||||
|
except KeyError:
|
||||||
|
self.derefRes[str(deref_attr)] = [(str(deref_val),partial_attrs_dict)]
|
||||||
|
|
||||||
|
|
||||||
|
KNOWN_RESPONSE_CONTROLS[DereferenceControl.controlType] = DereferenceControl
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
ldap.controls.openldap - classes for OpenLDAP-specific controls
|
ldap.controls.openldap - classes for OpenLDAP-specific controls
|
||||||
|
|
||||||
See http://www.python-ldap.org/ for project details.
|
See http://www.python-ldap.org/ for project details.
|
||||||
|
|
||||||
$Id: openldap.py,v 1.3 2015/06/22 17:56:50 stroeder Exp $
|
$Id: openldap.py,v 1.4 2015/09/18 17:24:39 stroeder Exp $
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import ldap.controls
|
import ldap.controls
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#!/usr/bin/env python
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
ldap.controls.readentry - classes for the Read Entry controls
|
ldap.controls.readentry - classes for the Read Entry controls
|
||||||
(see RFC 4527)
|
(see RFC 4527)
|
||||||
|
|
||||||
See http://www.python-ldap.org/ for project details.
|
See http://www.python-ldap.org/ for project details.
|
||||||
|
|
||||||
$Id: readentry.py,v 1.4 2011/07/28 08:57:12 stroeder Exp $
|
$Id: readentry.py,v 1.5 2015/09/18 17:24:55 stroeder Exp $
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import ldap
|
import ldap
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
ldap.controls.sessiontrack - class for session tracking control
|
ldap.controls.sessiontrack - class for session tracking control
|
||||||
(see draft-wahl-ldap-session)
|
(see draft-wahl-ldap-session)
|
||||||
|
|
||||||
See http://www.python-ldap.org/ for project details.
|
See http://www.python-ldap.org/ for project details.
|
||||||
|
|
||||||
$Id: sessiontrack.py,v 1.4 2013/07/04 16:20:06 stroeder Exp $
|
$Id: sessiontrack.py,v 1.5 2015/09/18 17:25:07 stroeder Exp $
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from ldap.controls import RequestControl
|
from ldap.controls import RequestControl
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ldapobject.py - wraps class _ldap.LDAPObject
|
|||||||
|
|
||||||
See http://www.python-ldap.org/ for details.
|
See http://www.python-ldap.org/ for details.
|
||||||
|
|
||||||
\$Id: ldapobject.py,v 1.146 2015/06/11 15:13:43 stroeder Exp $
|
\$Id: ldapobject.py,v 1.147 2015/08/08 13:37:41 stroeder Exp $
|
||||||
|
|
||||||
Compability:
|
Compability:
|
||||||
- Tested with Python 2.0+ but should work with Python 1.5.x
|
- Tested with Python 2.0+ but should work with Python 1.5.x
|
||||||
@@ -847,7 +847,7 @@ class SimpleLDAPObject:
|
|||||||
if r:
|
if r:
|
||||||
return r[0][1]
|
return r[0][1]
|
||||||
else:
|
else:
|
||||||
raise ldap.NO_SUCH_OBJECT('Empty search result reading entry %s' % (repr(dn)))
|
return None
|
||||||
|
|
||||||
def read_subschemasubentry_s(self,subschemasubentry_dn,attrs=None):
|
def read_subschemasubentry_s(self,subschemasubentry_dn,attrs=None):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ldap.resiter - processing LDAP results with iterators
|
|||||||
|
|
||||||
See http://www.python-ldap.org/ for details.
|
See http://www.python-ldap.org/ for details.
|
||||||
|
|
||||||
\$Id: resiter.py,v 1.6 2011/07/28 08:23:32 stroeder Exp $
|
\$Id: resiter.py,v 1.7 2015/09/18 20:20:32 stroeder Exp $
|
||||||
|
|
||||||
Python compability note:
|
Python compability note:
|
||||||
Requires Python 2.3+
|
Requires Python 2.3+
|
||||||
@@ -15,15 +15,15 @@ class ResultProcessor:
|
|||||||
Mix-in class used with ldap.ldapopbject.LDAPObject or derived classes.
|
Mix-in class used with ldap.ldapopbject.LDAPObject or derived classes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def allresults(self,msgid,timeout=-1):
|
def allresults(self,msgid,timeout=-1,add_ctrls=0):
|
||||||
"""
|
"""
|
||||||
Generator function which returns an iterator for processing all LDAP operation
|
Generator function which returns an iterator for processing all LDAP operation
|
||||||
results of the given msgid retrieved with LDAPObject.result3() -> 4-tuple
|
results of the given msgid retrieved with LDAPObject.result3() -> 4-tuple
|
||||||
"""
|
"""
|
||||||
result_type,result_list,result_msgid,result_serverctrls = self.result3(msgid,0,timeout)
|
result_type,result_list,result_msgid,result_serverctrls,_,_ = self.result4(msgid,0,timeout,add_ctrls=add_ctrls)
|
||||||
while result_type and result_list:
|
while result_type and result_list:
|
||||||
# Loop over list of search results
|
# Loop over list of search results
|
||||||
for result_item in result_list:
|
for result_item in result_list:
|
||||||
yield (result_type,result_list,result_msgid,result_serverctrls)
|
yield (result_type,result_list,result_msgid,result_serverctrls)
|
||||||
result_type,result_list,result_msgid,result_serverctrls = self.result3(msgid,0,timeout)
|
result_type,result_list,result_msgid,result_serverctrls,_,_ = self.result4(msgid,0,timeout,add_ctrls=add_ctrls)
|
||||||
return # allresults()
|
return # allresults()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ldap.schema.subentry - subschema subentry handling
|
|||||||
|
|
||||||
See http://www.python-ldap.org/ for details.
|
See http://www.python-ldap.org/ for details.
|
||||||
|
|
||||||
\$Id: subentry.py,v 1.35 2015/06/06 09:21:38 stroeder Exp $
|
\$Id: subentry.py,v 1.36 2015/08/08 14:13:30 stroeder Exp $
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import ldap.cidict,ldap.schema
|
import ldap.cidict,ldap.schema
|
||||||
@@ -481,6 +481,7 @@ def urlfetch(uri,trace_level=0,bytes_mode=None):
|
|||||||
subschemasubentry_dn,s_temp = ldif_parser.all_records[0]
|
subschemasubentry_dn,s_temp = ldif_parser.all_records[0]
|
||||||
# Work-around for mixed-cased attribute names
|
# Work-around for mixed-cased attribute names
|
||||||
subschemasubentry_entry = ldap.cidict.cidict()
|
subschemasubentry_entry = ldap.cidict.cidict()
|
||||||
|
s_temp = s_temp or {}
|
||||||
for at,av in s_temp.items():
|
for at,av in s_temp.items():
|
||||||
if at in SCHEMA_CLASS_MAPPING:
|
if at in SCHEMA_CLASS_MAPPING:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ldapurl - handling of LDAP URLs as described in RFC 4516
|
|||||||
|
|
||||||
See http://www.python-ldap.org/ for details.
|
See http://www.python-ldap.org/ for details.
|
||||||
|
|
||||||
\$Id: ldapurl.py,v 1.72 2015/06/06 09:21:37 stroeder Exp $
|
\$Id: ldapurl.py,v 1.73 2015/08/08 13:36:30 stroeder Exp $
|
||||||
|
|
||||||
Python compability note:
|
Python compability note:
|
||||||
This module only works with Python 2.0+ since
|
This module only works with Python 2.0+ since
|
||||||
@@ -11,7 +11,7 @@ This module only works with Python 2.0+ since
|
|||||||
2. list comprehensions are used.
|
2. list comprehensions are used.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = '2.4.20'
|
__version__ = '2.4.21'
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
# constants
|
# constants
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ ldif - generate and parse LDIF data (see RFC 2849)
|
|||||||
|
|
||||||
See http://www.python-ldap.org/ for details.
|
See http://www.python-ldap.org/ for details.
|
||||||
|
|
||||||
$Id: ldif.py,v 1.82 2015/06/21 11:38:32 stroeder Exp $
|
$Id: ldif.py,v 1.83 2015/08/08 13:36:30 stroeder Exp $
|
||||||
|
|
||||||
Python compability note:
|
Python compability note:
|
||||||
Tested with Python 2.0+, but should work with Python 1.5.2+.
|
Tested with Python 2.0+, but should work with Python 1.5.2+.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = '2.4.20'
|
__version__ = '2.4.21'
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
# constants
|
# constants
|
||||||
|
|||||||
132
Tests/t_ldif.py
Normal file
132
Tests/t_ldif.py
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
import ldif
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from StringIO import StringIO
|
||||||
|
except ImportError:
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
|
|
||||||
|
class TestParse(unittest.TestCase):
|
||||||
|
maxDiff = None
|
||||||
|
|
||||||
|
def check_ldif_to_records(self, ldif_string, expected):
|
||||||
|
#import pdb; pdb.set_trace()
|
||||||
|
got = ldif.ParseLDIF(StringIO(ldif_string))
|
||||||
|
self.assertEqual(got, expected)
|
||||||
|
|
||||||
|
def check_records_to_ldif(self, records, expected):
|
||||||
|
f = StringIO()
|
||||||
|
ldif_writer = ldif.LDIFWriter(f)
|
||||||
|
for dn, attrs in records:
|
||||||
|
ldif_writer.unparse(dn, attrs)
|
||||||
|
got = f.getvalue()
|
||||||
|
self.assertEqual(got, expected)
|
||||||
|
|
||||||
|
def check_roundtrip(self, ldif_source, records, ldif_expected=None):
|
||||||
|
ldif_source = textwrap.dedent(ldif_source).lstrip() + '\n'
|
||||||
|
if ldif_expected is None:
|
||||||
|
ldif_expected = ldif_source
|
||||||
|
else:
|
||||||
|
ldif_expected = textwrap.dedent(ldif_expected).lstrip() + '\n'
|
||||||
|
|
||||||
|
self.check_ldif_to_records(ldif_source, records)
|
||||||
|
self.check_records_to_ldif(records, ldif_expected)
|
||||||
|
self.check_ldif_to_records(ldif_expected, records)
|
||||||
|
|
||||||
|
def test_simple(self):
|
||||||
|
self.check_roundtrip("""
|
||||||
|
dn: cn=x,cn=y,cn=z
|
||||||
|
attrib: value
|
||||||
|
attrib: value2
|
||||||
|
""", [
|
||||||
|
('cn=x,cn=y,cn=z', {'attrib': [b'value', b'value2']}),
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_multiple(self):
|
||||||
|
self.check_roundtrip("""
|
||||||
|
dn: cn=x,cn=y,cn=z
|
||||||
|
a: v
|
||||||
|
attrib: value
|
||||||
|
attrib: value2
|
||||||
|
|
||||||
|
dn: cn=a,cn=b,cn=c
|
||||||
|
attrib: value2
|
||||||
|
attrib: value3
|
||||||
|
b: v
|
||||||
|
""", [
|
||||||
|
('cn=x,cn=y,cn=z', {'attrib': [b'value', b'value2'], 'a': [b'v']}),
|
||||||
|
('cn=a,cn=b,cn=c', {'attrib': [b'value2', b'value3'], 'b': [b'v']}),
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_folded(self):
|
||||||
|
self.check_roundtrip("""
|
||||||
|
dn: cn=x,cn=y,cn=z
|
||||||
|
attrib: very
|
||||||
|
long
|
||||||
|
value
|
||||||
|
attrib2: %s
|
||||||
|
""" % ('asdf.' * 20), [
|
||||||
|
('cn=x,cn=y,cn=z', {'attrib': [b'verylong value'],
|
||||||
|
'attrib2': [b'asdf.' * 20]}),
|
||||||
|
], """
|
||||||
|
dn: cn=x,cn=y,cn=z
|
||||||
|
attrib: verylong value
|
||||||
|
attrib2: asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.as
|
||||||
|
df.asdf.asdf.asdf.asdf.asdf.asdf.
|
||||||
|
""")
|
||||||
|
|
||||||
|
def test_empty(self):
|
||||||
|
self.check_roundtrip("""
|
||||||
|
dn: cn=x,cn=y,cn=z
|
||||||
|
attrib:
|
||||||
|
attrib: foo
|
||||||
|
""", [
|
||||||
|
('cn=x,cn=y,cn=z', {'attrib': [b'', b'foo']}),
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_binary(self):
|
||||||
|
self.check_roundtrip("""
|
||||||
|
dn: cn=x,cn=y,cn=z
|
||||||
|
attrib:: CQAKOiVA
|
||||||
|
""", [
|
||||||
|
('cn=x,cn=y,cn=z', {'attrib': [b'\t\0\n:%@']}),
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_unicode(self):
|
||||||
|
self.check_roundtrip("""
|
||||||
|
dn: cn=Michael Stroeder,dc=stroeder,dc=com
|
||||||
|
lastname: Ströder
|
||||||
|
""", [
|
||||||
|
('cn=Michael Stroeder,dc=stroeder,dc=com',
|
||||||
|
{'lastname': [b'Str\303\266der']}),
|
||||||
|
], """
|
||||||
|
dn: cn=Michael Stroeder,dc=stroeder,dc=com
|
||||||
|
lastname:: U3Ryw7ZkZXI=
|
||||||
|
""")
|
||||||
|
|
||||||
|
def test_sorted(self):
|
||||||
|
self.check_roundtrip("""
|
||||||
|
dn: cn=x,cn=y,cn=z
|
||||||
|
b: value_b
|
||||||
|
c: value_c
|
||||||
|
a: value_a
|
||||||
|
""", [
|
||||||
|
('cn=x,cn=y,cn=z', {'a': [b'value_a'],
|
||||||
|
'b': [b'value_b'],
|
||||||
|
'c': [b'value_c']}),
|
||||||
|
], """
|
||||||
|
dn: cn=x,cn=y,cn=z
|
||||||
|
a: value_a
|
||||||
|
b: value_b
|
||||||
|
c: value_c
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
3
setup.py
3
setup.py
@@ -3,7 +3,7 @@ setup.py - Setup package with the help Python's DistUtils
|
|||||||
|
|
||||||
See http://www.python-ldap.org/ for details.
|
See http://www.python-ldap.org/ for details.
|
||||||
|
|
||||||
$Id: setup.py,v 1.72 2014/03/12 20:29:23 stroeder Exp $
|
$Id: setup.py,v 1.73 2015/09/19 13:38:30 stroeder Exp $
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys,os,string,time
|
import sys,os,string,time
|
||||||
@@ -164,6 +164,7 @@ setup(
|
|||||||
'ldap.async',
|
'ldap.async',
|
||||||
'ldap.compat',
|
'ldap.compat',
|
||||||
'ldap.controls',
|
'ldap.controls',
|
||||||
|
'ldap.controls.deref',
|
||||||
'ldap.controls.libldap',
|
'ldap.controls.libldap',
|
||||||
'ldap.controls.openldap',
|
'ldap.controls.openldap',
|
||||||
'ldap.controls.ppolicy',
|
'ldap.controls.ppolicy',
|
||||||
|
|||||||
Reference in New Issue
Block a user