Package ldaptor :: Module schema
[hide private]
[frames] | no frames]

Source Code for Module ldaptor.schema

1 -def extractWord(text):
2 if not text: 3 return None 4 l = text.split(None, 1) 5 word = l[0] 6 try: 7 text = l[1] 8 except IndexError: 9 text = '' 10 return word, text
11
12 -def peekWord(text):
13 if not text: 14 return None 15 return text.split(None, 1)[0]
16
17 -class ASN1ParserThingie:
18 - def _to_list(self, text):
19 """Split text into $-separated list.""" 20 r=[] 21 for x in text.split("$"): 22 x = x.strip() 23 assert x 24 r.append(x) 25 return tuple(r)
26
27 - def _strings_to_list(self, text):
28 """Split ''-quoted strings into list.""" 29 r=[] 30 while text: 31 text = text.lstrip() 32 if not text: 33 break 34 assert text[0]=="'", "Text %s must start with a single quote."%repr(text) 35 text=text[1:] 36 end=text.index("'") 37 r.append(text[:end]) 38 text=text[end+1:] 39 return tuple(r)
40
41 - def _str_list(self, l):
42 s = ' '.join([self._str(x) for x in l]) 43 if len(l) > 1: 44 s = '( %s )' % s 45 return s
46
47 - def _list(self, l):
48 s = ' $ '.join([x for x in l]) 49 if len(l) > 1: 50 s = '( %s )' % s 51 return s
52
53 - def _str(self, s):
54 return "'%s'" % s
55
56 -class ObjectClassDescription(ASN1ParserThingie):
57 """ 58 ASN Syntax:: 59 60 d = "0" / "1" / "2" / "3" / "4" / 61 "5" / "6" / "7" / "8" / "9" 62 63 numericstring = 1*d 64 65 numericoid = numericstring *( "." numericstring ) 66 67 space = 1*" " 68 69 whsp = [ space ] 70 71 descr = keystring 72 73 qdescr = whsp "'" descr "'" whsp 74 75 qdescrlist = [ qdescr *( qdescr ) ] 76 77 ; object descriptors used as schema element names 78 qdescrs = qdescr / ( whsp "(" qdescrlist ")" whsp ) 79 80 dstring = 1*utf8 81 82 qdstring = whsp "'" dstring "'" whsp 83 84 descr = keystring 85 86 oid = descr / numericoid 87 88 woid = whsp oid whsp 89 90 ; set of oids of either form 91 oids = woid / ( "(" oidlist ")" ) 92 93 ObjectClassDescription = "(" whsp 94 numericoid whsp ; ObjectClass identifier 95 [ "NAME" qdescrs ] 96 [ "DESC" qdstring ] 97 [ "OBSOLETE" whsp ] 98 [ "SUP" oids ] ; Superior ObjectClasses 99 [ ( "ABSTRACT" / "STRUCTURAL" / "AUXILIARY" ) whsp ] 100 ; default structural 101 [ "MUST" oids ] ; AttributeTypes 102 [ "MAY" oids ] ; AttributeTypes 103 whsp ")" 104 """ 105 106
107 - def __init__(self, text):
108 self.oid=None 109 self.name=None 110 self.desc=None 111 self.obsolete=0 112 self.sup=[] 113 self.type=None 114 self.must=[] 115 self.may=[] 116 117 if text is not None: 118 self._parse(text)
119
120 - def _parse(self, text):
121 assert text[0]=='(', "Text %s must be in parentheses."%repr(text) 122 assert text[-1]==')', "Text %s must be in parentheses."%repr(text) 123 text=text[1:-1] 124 text = text.lstrip() 125 126 # oid 127 self.oid, text = extractWord(text) 128 129 text = text.lstrip() 130 131 if peekWord(text) == "NAME": 132 text=text[len("NAME "):] 133 text = text.lstrip() 134 if text[0]=="'": 135 text=text[1:] 136 end=text.index("'") 137 self.name=(text[:end],) 138 text=text[end+1:] 139 elif text[0]=="(": 140 text=text[1:] 141 text = text.lstrip() 142 end=text.index(")") 143 self.name=self._strings_to_list(text[:end]) 144 text=text[end+1:] 145 else: 146 raise "TODO" 147 148 149 text = text.lstrip() 150 151 if peekWord(text) == "DESC": 152 text=text[len("DESC "):] 153 text = text.lstrip() 154 assert text[0]=="'" 155 text=text[1:] 156 end=text.index("'") 157 self.desc=text[:end] 158 text=text[end+1:] 159 160 text = text.lstrip() 161 162 if peekWord(text) == "OBSOLETE": 163 self.obsolete=1 164 text=text[len("OBSOLETE "):] 165 166 text = text.lstrip() 167 168 if peekWord(text) == "SUP": 169 text=text[len("SUP "):] 170 text = text.lstrip() 171 if text[0]=="(": 172 text=text[1:] 173 text = text.lstrip() 174 end=text.index(")") 175 self.sup=self._to_list(text[:end]) 176 text=text[end+1:] 177 else: 178 s, text = extractWord(text) 179 self.sup=[s] 180 181 text = text.lstrip() 182 183 if peekWord(text) == "ABSTRACT": 184 assert self.type is None 185 self.type="ABSTRACT" 186 text=text[len("ABSTRACT "):] 187 188 text = text.lstrip() 189 190 if peekWord(text) == "STRUCTURAL": 191 assert self.type is None 192 self.type="STRUCTURAL" 193 text=text[len("STRUCTURAL "):] 194 195 text = text.lstrip() 196 197 if peekWord(text) == "AUXILIARY": 198 assert self.type is None 199 self.type="AUXILIARY" 200 text=text[len("AUXILIARY "):] 201 202 text = text.lstrip() 203 204 if peekWord(text) == "MUST": 205 text=text[len("MUST "):] 206 text = text.lstrip() 207 if text[0]=="(": 208 text=text[1:] 209 text = text.lstrip() 210 end=text.index(")") 211 self.must.extend(self._to_list(text[:end])) 212 text=text[end+1:] 213 else: 214 s, text = extractWord(text) 215 self.must.append(s) 216 217 text = text.lstrip() 218 219 if peekWord(text) == "MAY": 220 text=text[len("MAY "):] 221 text = text.lstrip() 222 if text[0]=="(": 223 text=text[1:] 224 text = text.lstrip() 225 end=text.index(")") 226 self.may.extend(self._to_list(text[:end])) 227 text=text[end+1:] 228 else: 229 s, text = extractWord(text) 230 self.may.append(s) 231 232 text = text.lstrip() 233 234 assert text=="", "Text was not empty: %s"%repr(text) 235 236 if not self.type: 237 self.type="STRUCTURAL" 238 239 assert self.oid 240 for c in self.oid: 241 assert c in "0123456789." 242 assert self.name is None or self.name 243 assert self.type in ("ABSTRACT", "STRUCTURAL", "AUXILIARY")
244
245 - def __repr__(self):
246 nice = {} 247 for k,v in self.__dict__.items(): 248 nice[k]=repr(v) 249 return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self)) 250 +(" oid=%(oid)s name=%(name)s desc=%(desc)s" 251 +" obsolete=%(obsolete)s sup=%(sup)s type=%(type)s" 252 +" must=%(must)s may=%(may)s>")%nice)
253
254 - def __str__(self):
255 r=[] 256 if self.name is not None: 257 r.append('NAME %s' % self._str_list(self.name)) 258 if self.desc is not None: 259 r.append('DESC %s' % self._str(self.desc)) 260 if self.obsolete: 261 r.append('OBSOLETE') 262 if self.sup: 263 r.append('SUP %s' % self._list(self.sup)) 264 r.append('%s' % self.type) 265 if self.must: 266 r.append('MUST %s' % self._list(self.must)) 267 if self.may: 268 r.append('MAY %s' % self._list(self.may)) 269 return ('( %s ' % self.oid 270 + '\n '.join(r) 271 + ' )')
272
273 - def __lt__(self, other):
274 if not isinstance(other, ObjectClassDescription): 275 return NotImplemented 276 if self.name is not None and other.name is not None: 277 return self.name[0].upper() < other.name[0].upper() 278 else: 279 return self.oid < other.oid
280
281 - def __gt__(self, other):
282 if not isinstance(other, ObjectClassDescription): 283 return NotImplemented 284 if self.name is not None and other.name is not None: 285 return self.name[0].upper() > other.name[0].upper() 286 else: 287 return self.oid > other.oid
288
289 - def __le__(self, other):
290 return self == other or self < other
291
292 - def __ge__(self, other):
293 return self == other or self > other
294
295 - def __eq__(self, other):
296 if not isinstance(other, ObjectClassDescription): 297 return NotImplemented 298 return (self.oid == other.oid 299 and self.name == other.name 300 and self.desc == other.desc 301 and self.obsolete == other.obsolete 302 and self.sup == other.sup 303 and self.type == other.type 304 and self.must == other.must 305 and self.may == other.may)
306
307 - def __ne__(self, other):
308 return not (self == other)
309
310 -class AttributeTypeDescription(ASN1ParserThingie):
311 """ 312 ASN Syntax:: 313 314 AttributeTypeDescription = "(" whsp 315 numericoid whsp ; AttributeType identifier 316 [ "NAME" qdescrs ] ; name used in AttributeType 317 [ "DESC" qdstring ] ; description 318 [ "OBSOLETE" whsp ] 319 [ "SUP" woid ] ; derived from this other AttributeType 320 [ "EQUALITY" woid ; Matching Rule name 321 [ "ORDERING" woid ; Matching Rule name 322 [ "SUBSTR" woid ] ; Matching Rule name 323 [ "SYNTAX" whsp noidlen whsp ] ; see section 4.3 324 [ "SINGLE-VALUE" whsp ] ; default multi-valued 325 [ "COLLECTIVE" whsp ] ; default not collective 326 [ "NO-USER-MODIFICATION" whsp ]; default user modifiable 327 [ "USAGE" whsp AttributeUsage ]; default userApplications 328 whsp ")" 329 330 AttributeUsage = 331 "userApplications" / 332 "directoryOperation" / 333 "distributedOperation" / ; DSA-shared 334 "dSAOperation" ; DSA-specific, value depends on server 335 336 noidlen = numericoid [ "{" len "}" ] 337 338 len = numericstring 339 """ 340
341 - def __init__(self, text):
342 self.oid=None 343 self.name=None 344 self.desc=None 345 self.obsolete=0 346 self.sup=None 347 self.equality=None 348 self.ordering=None 349 self.substr=None 350 self.syntax=None 351 self.single_value=None 352 self.collective=None 353 self.no_user_modification=None 354 self.usage=None 355 356 if text is not None: 357 self._parse(text)
358
359 - def _parse(self, text):
360 assert text[0]=='(', "Text %s must be in parentheses."%repr(text) 361 assert text[-1]==')', "Text %s must be in parentheses."%repr(text) 362 text=text[1:-1] 363 text = text.lstrip() 364 365 # oid 366 self.oid, text = extractWord(text) 367 368 text = text.lstrip() 369 370 if peekWord(text) == "NAME": 371 text=text[len("NAME "):] 372 text = text.lstrip() 373 if text[0]=="'": 374 text=text[1:] 375 end=text.index("'") 376 self.name=(text[:end],) 377 text=text[end+1:] 378 elif text[0]=="(": 379 text=text[1:] 380 text = text.lstrip() 381 end=text.index(")") 382 self.name=self._strings_to_list(text[:end]) 383 text=text[end+1:] 384 else: 385 raise "TODO" 386 387 388 text = text.lstrip() 389 390 if peekWord(text) == "DESC": 391 text=text[len("DESC "):] 392 text = text.lstrip() 393 assert text[0]=="'" 394 text=text[1:] 395 end=text.index("'") 396 self.desc=text[:end] 397 text=text[end+1:] 398 399 text = text.lstrip() 400 401 if peekWord(text) == "OBSOLETE": 402 self.obsolete=1 403 text=text[len("OBSOLETE "):] 404 405 text = text.lstrip() 406 407 if peekWord(text) == "SUP": 408 text=text[len("SUP "):] 409 text = text.lstrip() 410 self.sup, text = extractWord(text) 411 412 text = text.lstrip() 413 414 if peekWord(text) == "EQUALITY": 415 text=text[len("EQUALITY "):] 416 text = text.lstrip() 417 self.equality, text = extractWord(text) 418 419 text = text.lstrip() 420 421 if peekWord(text) == "ORDERING": 422 text=text[len("ORDERING "):] 423 text = text.lstrip() 424 self.ordering, text = extractWord(text) 425 426 text = text.lstrip() 427 428 if peekWord(text) == "SUBSTR": 429 text=text[len("SUBSTR "):] 430 text = text.lstrip() 431 self.substr, text = extractWord(text) 432 433 text = text.lstrip() 434 435 if peekWord(text) == "SYNTAX": 436 text=text[len("SYNTAX "):] 437 text = text.lstrip() 438 self.syntax, text = extractWord(text) 439 440 text = text.lstrip() 441 442 if peekWord(text) == "SINGLE-VALUE": 443 assert self.single_value is None 444 self.single_value=1 445 text=text[len("SINGLE-VALUE "):] 446 447 text = text.lstrip() 448 449 if peekWord(text) == "COLLECTIVE": 450 assert self.collective is None 451 self.collective=1 452 text=text[len("COLLECTIVE "):] 453 454 text = text.lstrip() 455 456 if peekWord(text) == "NO-USER-MODIFICATION": 457 assert self.no_user_modification is None 458 self.no_user_modification=1 459 text=text[len("NO-USER-MODIFICATION "):] 460 461 text = text.lstrip() 462 463 if peekWord(text) == "USAGE": 464 assert self.usage is None 465 text=text[len("USAGE "):] 466 text = text.lstrip() 467 self.usage, text = extractWord(text) 468 469 text = text.lstrip() 470 471 assert text=="", "Text was not empty: %s"%repr(text) 472 473 if self.single_value is None: 474 self.single_value=0 475 476 if self.collective is None: 477 self.collective=0 478 479 if self.no_user_modification is None: 480 self.no_user_modification=0 481 482 assert self.oid 483 for c in self.oid: 484 assert c in "0123456789." 485 assert self.name is None or self.name 486 assert self.usage is None or self.usage in ( 487 "userApplications", 488 "directoryOperation", 489 "distributedOperation", 490 "dSAOperation", 491 )
492
493 - def __repr__(self):
494 nice = {} 495 for k,v in self.__dict__.items(): 496 nice[k]=repr(v) 497 return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self)) 498 +(" oid=%(oid)s name=%(name)s desc=%(desc)s" 499 +" obsolete=%(obsolete)s sup=%(sup)s" 500 +" equality=%(equality)s ordering=%(ordering)s" 501 +" substr=%(substr)s syntax=%(syntax)s" 502 +" single_value=%(single_value)s" 503 +" collective=%(collective)s" 504 +" no_user_modification=%(no_user_modification)s" 505 +" usage=%(usage)s>")%nice)
506
507 - def __str__(self):
508 r=[] 509 if self.name is not None: 510 r.append('NAME %s' % self._str_list(self.name)) 511 if self.desc is not None: 512 r.append('DESC %s' % self._str(self.desc)) 513 if self.obsolete: 514 r.append('OBSOLETE') 515 if self.sup is not None: 516 r.append('SUP %s' % self.sup) 517 if self.equality is not None: 518 r.append('EQUALITY %s' % self.equality) 519 if self.ordering is not None: 520 r.append('ORDERING %s' % self.ordering) 521 if self.substr is not None: 522 r.append('SUBSTR %s' % self.substr) 523 if self.syntax is not None: 524 r.append('SYNTAX %s' % self.syntax) 525 if self.single_value: 526 r.append('SINGLE-VALUE') 527 if self.collective: 528 r.append('COLLECTIVE') 529 if self.no_user_modification: 530 r.append('NO-USER-MODIFICATION') 531 if self.usage is not None: 532 r.append('USAGE %s' % self.usage) 533 return ('( %s ' % self.oid 534 + '\n '.join(r) 535 + ' )')
536
537 -class SyntaxDescription(ASN1ParserThingie):
538 """ 539 ASN Syntax:: 540 541 SyntaxDescription = "(" whsp 542 numericoid whsp 543 [ "DESC" qdstring ] 544 whsp ")" 545 """ 546
547 - def __init__(self, text):
548 self.oid=None 549 self.desc=None 550 551 assert text[0]=='(' 552 assert text[-1]==')' 553 text=text[1:-1] 554 text = text.lstrip() 555 556 # oid 557 self.oid, text = extractWord(text) 558 559 text = text.lstrip() 560 561 if peekWord(text) == "DESC": 562 text=text[len("DESC "):] 563 text = text.lstrip() 564 assert text[0]=="'" 565 text=text[1:] 566 end=text.index("'") 567 self.desc=text[:end] 568 text=text[end+1:] 569 570 text = text.lstrip() 571 572 if peekWord(text) == "X-BINARY-TRANSFER-REQUIRED": 573 text=text[len("X-BINARY-TRANSFER-REQUIRED "):] 574 text = text.lstrip() 575 assert text[0]=="'" 576 text=text[1:] 577 end=text.index("'") 578 self.desc=text[:end] 579 text=text[end+1:] 580 581 text = text.lstrip() 582 583 if peekWord(text) == "X-NOT-HUMAN-READABLE": 584 text=text[len("X-NOT-HUMAN-READABLE "):] 585 text = text.lstrip() 586 assert text[0]=="'" 587 text=text[1:] 588 end=text.index("'") 589 self.desc=text[:end] 590 text=text[end+1:] 591 592 text = text.lstrip() 593 594 assert text=="", "Text was not empty: %s"%repr(text) 595 596 assert self.oid 597 for c in self.oid: 598 assert c in "0123456789."
599
600 - def __repr__(self):
601 nice = {} 602 for k,v in self.__dict__.items(): 603 nice[k]=repr(v) 604 return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self)) 605 +(" oid=%(oid)s desc=%(desc)s>")%nice)
606 607 608
609 -class MatchingRuleDescription(ASN1ParserThingie):
610 """ 611 ASN Syntax:: 612 613 MatchingRuleDescription = "(" whsp 614 numericoid whsp ; MatchingRule identifier 615 [ "NAME" qdescrs ] 616 [ "DESC" qdstring ] 617 [ "OBSOLETE" whsp ] 618 "SYNTAX" numericoid 619 whsp ")" 620 """ 621
622 - def __init__(self, text):
623 self.oid=None 624 self.name=None 625 self.desc=None 626 self.obsolete=None 627 self.syntax=None 628 629 assert text[0]=='(' 630 assert text[-1]==')' 631 text=text[1:-1] 632 text = text.lstrip() 633 634 # oid 635 self.oid, text = extractWord(text) 636 637 text = text.lstrip() 638 639 if peekWord(text) == "NAME": 640 text=text[len("NAME "):] 641 text = text.lstrip() 642 if text[0]=="'": 643 text=text[1:] 644 end=text.index("'") 645 self.name=(text[:end],) 646 text=text[end+1:] 647 elif text[0]=="(": 648 text=text[1:] 649 text = text.lstrip() 650 end=text.index(")") 651 self.name=self._strings_to_list(text[:end]) 652 text=text[end+1:] 653 else: 654 raise "TODO" 655 656 text = text.lstrip() 657 658 if peekWord(text) == "DESC": 659 text=text[len("DESC "):] 660 text = text.lstrip() 661 assert text[0]=="'" 662 text=text[1:] 663 end=text.index("'") 664 self.desc=text[:end] 665 text=text[end+1:] 666 667 text = text.lstrip() 668 669 if peekWord(text) == "OBSOLETE": 670 self.obsolete=1 671 text=text[len("OBSOLETE "):] 672 673 text = text.lstrip() 674 675 if peekWord(text) == "SYNTAX": 676 text=text[len("SYNTAX "):] 677 text = text.lstrip() 678 self.syntax, text = extractWord(text) 679 680 text = text.lstrip() 681 682 assert text=="", "Text was not empty: %s"%repr(text) 683 684 if self.obsolete is None: 685 self.obsolete=0 686 assert self.oid 687 for c in self.oid: 688 assert c in "0123456789." 689 assert self.syntax
690
691 - def __repr__(self):
692 nice = {} 693 for k,v in self.__dict__.items(): 694 nice[k]=repr(v) 695 return ("<%s instance at 0x%x"%(self.__class__.__name__, id(self)) 696 +(" oid=%(oid)s desc=%(desc)s>")%nice)
697