tessl install tessl/pypi-ldap3@1.4.0A strictly RFC 4510 conforming LDAP V3 pure Python client library
Agent Success
Agent success rate when using this tile
81%
Improvement
Agent success rate improvement when using this tile compared to baseline
1.08x
Baseline
Agent success rate without this tile
75%
Build a small module that turns planned directory updates into LDIF change records and streams LDIF content exports without contacting any LDAP server. The module must return LDIF text and optionally write the same text to a provided path or open stream. Use the target package to produce the LDIF output rather than manual string assembly.
Given two operations — an add of cn=Alice,dc=example,dc=org with attributes objectClass: inetOrgPerson, cn: Alice Doe, sn: Doe, mail: alice@example.org, and a modify replace of telephoneNumber on cn=Bob,dc=example,dc=org with value +1 555 2000 — the returned LDIF change text matches exactly:
dn: cn=Alice,dc=example,dc=org
changetype: add
objectClass: inetOrgPerson
cn: Alice Doe
sn: Doe
mail: alice@example.org
dn: cn=Bob,dc=example,dc=org
changetype: modify
replace: telephoneNumber
telephoneNumber: +1 555 2000
-@test
Exporting two entries with attribute order ["dn", "objectClass", "cn", "sn", "mail"] produces content LDIF that preserves that order and appends any extra attributes afterward. For entries cn=Carol,dc=example,dc=org (attributes objectClass: inetOrgPerson, cn: Carol, sn: Collins, mail: carol@example.org, telephoneNumber: +1 555 3000) and cn=Dan,dc=example,dc=org (attributes objectClass: inetOrgPerson, cn: Dan, sn: Diaz, mail: dan@example.org), the output matches:
dn: cn=Carol,dc=example,dc=org
objectClass: inetOrgPerson
cn: Carol
sn: Collins
mail: carol@example.org
telephoneNumber: +1 555 3000
dn: cn=Dan,dc=example,dc=org
objectClass: inetOrgPerson
cn: Dan
sn: Diaz
mail: dan@example.org@test
"\r\n" is passed as the line separator, every line in both change and content exports (including the final blank line between change records) uses CRLF endings with no stray bare \n characters. @test@generates
from typing import Iterable, Mapping, Sequence, TextIO, Union, Optional
Operation = Mapping[str, object]
Entry = Mapping[str, object]
def generate_change_ldif(
operations: Sequence[Operation],
target: Optional[Union[str, TextIO]] = None,
line_separator: str = "\n",
) -> str:
"""
Converts offline operations into LDIF change records in the order provided,
returns the LDIF text, and optionally writes it to a path or open stream.
Each operation includes:
- "dn": str
- "action": "add" or "modify"
- For "add": "attributes": Mapping[str, Union[str, Sequence[str]]]
- For "modify": "changes": Sequence[Mapping[str, Union[str, Sequence[str]]]] where each mapping has "attribute", "action" ("add"|"delete"|"replace"), and "values"
"""
def export_content_ldif(
entries: Sequence[Entry],
target: Union[str, TextIO],
line_separator: str = "\n",
attribute_order: Optional[Sequence[str]] = None,
) -> str:
"""
Writes LDIF content entries (no change directives) for the provided entries,
respecting attribute_order when given, and returns the LDIF text.
Each entry includes:
- "dn": str
- "attributes": Mapping[str, Union[str, Sequence[str]]]
"""Generate LDIF change and content output offline using the LDIF client strategy and related helpers. @satisfied-by