4545 0 :'add' ,1 :'delete' ,2 :'replace' ,3 :'increment'
4646}
4747
48- CHANGE_TYPES = ['add' ,'delete' ,'modify' ,'modrdn' ]
48+ CHANGE_TYPES = ['add' ,'delete' ,'modify' ,'modrdn' , 'moddn' , 'rename' ]
4949valid_changetype_dict = {}
5050for c in CHANGE_TYPES :
5151 valid_changetype_dict [c ]= None
@@ -459,6 +459,17 @@ def parse(self):
459459 """
460460 return self .parse_entry_records () # parse()
461461
462+ def handle_add (self , dn , entry , controls = None ):
463+ """
464+ Process a single LDIF record representing a single add operation.
465+ This method should be implemented by applications using LDIFParser.
466+
467+ Args:
468+ dn (str): DN of the new object to be created
469+ entry (dict): Data of the new object to be created
470+ """
471+ pass
472+
462473 def handle_modify (self ,dn ,modops ,controls = None ):
463474 """
464475 Process a single LDIF record representing a single modify operation.
@@ -467,6 +478,31 @@ def handle_modify(self,dn,modops,controls=None):
467478 controls = [] or None
468479 pass
469480
481+ def handle_modrdn (self , dn , newrdn , deleteoldrdn = False , newsuperior = None ,
482+ controls = None ):
483+ """
484+ Process a single LDIF record representing a single modrdn/rename operation.
485+ This method should be implemented by applications using LDIFParser.
486+
487+ Args:
488+ dn (str): DN of the existing object to be renamed/moved
489+ newrdn (str): RDN of the new object
490+ deleteoldrdn (bool): Whether the old RDN value(s) should be removed
491+ from the entry
492+ newsuperior (str): DN of the new parent
493+ """
494+ pass
495+
496+ def handle_delete (self , dn , controls = None ):
497+ """
498+ Process a single LDIF record representing a single delete operation.
499+ This method should be implemented by applications using LDIFParser.
500+
501+ Args:
502+ dn (str): DN of the existing object to be deleted
503+ """
504+ pass
505+
470506 def parse_change_records (self ):
471507 # Local symbol for better performance
472508 next_key_and_value = self ._next_key_and_value
@@ -509,7 +545,7 @@ def parse_change_records(self):
509545 # Consume changetype line of record
510546 if k == 'changetype' :
511547 # v is still bytes, spec says it should be valid utf-8; decode it.
512- v = v .decode ('utf-8' )
548+ v = v .decode ('utf-8' ). lower ()
513549 if not v in valid_changetype_dict :
514550 raise ValueError ('Invalid changetype: %s' % repr (v ))
515551 changetype = v
@@ -551,12 +587,60 @@ def parse_change_records(self):
551587 except EOFError :
552588 k ,v = None ,None
553589
554- if modops :
555- # append entry to result list
556- self .handle_modify (dn ,modops ,controls )
590+ self .handle_modify (dn , modops , controls or None )
557591
592+ elif changetype == 'add' :
593+ entry = {}
594+ while k != None :
595+ if not k .lower () in self ._ignored_attr_types :
596+ entry .setdefault (k , []).append (v )
597+ try :
598+ k ,v = next_key_and_value ()
599+ except EOFError :
600+ k ,v = None ,None
601+
602+ self .handle_add (dn ,entry , controls or None )
603+
604+ elif changetype == 'delete' :
605+ if k is not None :
606+ raise ValueError (f'Line { self .line_counter } : Unexpected '
607+ f'attribute { k } in LDIF delete' )
608+ self .handle_delete (dn , controls or None )
609+ elif changetype in ('moddn' , 'modrdn' , 'rename' ):
610+ if k .lower () != 'newrdn' :
611+ raise ValueError (f'Line { self .line_counter } : expected "newrdn"'
612+ f'got { k } ' )
613+ newrdn = v .decode ('utf-8' )
614+ k ,v = next_key_and_value ()
615+ deleteoldrdn = False
616+ if k is not None :
617+ if k .lower () == 'deleteoldrdn' :
618+ deleteoldrdn = (v == b'1' )
619+ try :
620+ k ,v = next_key_and_value ()
621+ except EOFError :
622+ k ,v = None ,None
623+ elif k .lower () == 'newsuperior' :
624+ pass
625+ else :
626+ raise ValueError (f'Line { self .line_counter } : expected '
627+ f'"deleteoldrdn" got { k } ' )
628+ newsuperior = None
629+ if k is not None :
630+ if k .lower () != 'newsuperior' :
631+ raise ValueError (f'Line { self .line_counter } : expected '
632+ f'"newsuperior" got { k } ' )
633+ newsuperior = v .decode ('utf-8' )
634+ try :
635+ k ,v = next_key_and_value ()
636+ except EOFError :
637+ k ,v = None ,None
638+ if k is not None :
639+ raise ValueError (f'Line { self .line_counter } : { changetype } entry '
640+ f'unexpected pseudoattribute { k } ' )
641+ self .handle_modrdn (dn , newrdn , deleteoldrdn , newsuperior ,
642+ controls or None )
558643 else :
559-
560644 # Consume the unhandled change record
561645 while k != None :
562646 k ,v = next_key_and_value ()
@@ -592,20 +676,48 @@ def __init__(
592676 #: List storing parsed records.
593677 self .all_records = []
594678 self .all_modify_changes = []
679+ self .all_changes = []
595680
596681 def handle (self ,dn ,entry ):
597682 """
598683 Append a single record to the list of all records (:attr:`.all_records`).
599684 """
600685 self .all_records .append ((dn ,entry ))
601686
687+ def handle_add (self , dn , entry , controls = None ):
688+ """
689+ Process a single LDIF record representing a single add operation.
690+ This method should be implemented by applications using LDIFParser.
691+ """
692+ self .all_changes .append (('add' , {'dn' : dn , 'entry' : entry ,
693+ 'controls' : controls }))
694+
602695 def handle_modify (self ,dn ,modops ,controls = None ):
603696 """
604697 Process a single LDIF record representing a single modify operation.
605698 This method should be implemented by applications using LDIFParser.
606699 """
607- controls = [] or None
608700 self .all_modify_changes .append ((dn ,modops ,controls ))
701+ self .all_changes .append (('modify' , {'dn' : dn , 'modops' : modops ,
702+ 'controls' : controls }))
703+
704+ def handle_modrdn (self , dn , newrdn , deleteoldrdn = False , newsuperior = None ,
705+ controls = None ):
706+ """
707+ Process a single LDIF record representing a single modrdn/rename operation.
708+ This method should be implemented by applications using LDIFParser.
709+ """
710+ self .all_changes .append (('modrdn' , {'dn' : dn , 'newrdn' : newrdn ,
711+ 'deleteoldrdn' : deleteoldrdn ,
712+ 'newsuperior' : newsuperior ,
713+ 'controls' : controls }))
714+
715+ def handle_delete (self , dn , controls = None ):
716+ """
717+ Process a single LDIF record representing a single delete operation.
718+ This method should be implemented by applications using LDIFParser.
719+ """
720+ self .all_changes .append (('delete' , {'dn' : dn , 'controls' : controls }))
609721
610722
611723class LDIFCopy (LDIFParser ):
0 commit comments