Package yadis :: Module xri
[hide private]
[frames] | no frames]

Source Code for Module yadis.xri

  1  # -*- test-case-name: yadis.test.test_xri -*- 
  2  """Utility functions for handling XRIs. 
  3   
  4  @see: XRI Syntax v2.0 at the U{OASIS XRI Technical Committee<http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xri>} 
  5  """ 
  6   
  7  import re 
  8   
  9  XRI_AUTHORITIES = ['!', '=', '@', '+', '$', '('] 
 10   
 11  try: 
 12      unichr(0x10000) 
 13  except ValueError: 
 14      # narrow python build 
 15      UCSCHAR = [ 
 16          (0xA0, 0xD7FF), 
 17          (0xF900, 0xFDCF), 
 18          (0xFDF0, 0xFFEF), 
 19          ] 
 20   
 21      IPRIVATE = [ 
 22          (0xE000, 0xF8FF), 
 23          ] 
 24  else: 
 25      UCSCHAR = [ 
 26          (0xA0, 0xD7FF), 
 27          (0xF900, 0xFDCF), 
 28          (0xFDF0, 0xFFEF), 
 29          (0x10000, 0x1FFFD), 
 30          (0x20000, 0x2FFFD), 
 31          (0x30000, 0x3FFFD), 
 32          (0x40000, 0x4FFFD), 
 33          (0x50000, 0x5FFFD), 
 34          (0x60000, 0x6FFFD), 
 35          (0x70000, 0x7FFFD), 
 36          (0x80000, 0x8FFFD), 
 37          (0x90000, 0x9FFFD), 
 38          (0xA0000, 0xAFFFD), 
 39          (0xB0000, 0xBFFFD), 
 40          (0xC0000, 0xCFFFD), 
 41          (0xD0000, 0xDFFFD), 
 42          (0xE1000, 0xEFFFD), 
 43          ] 
 44   
 45      IPRIVATE = [ 
 46          (0xE000, 0xF8FF), 
 47          (0xF0000, 0xFFFFD), 
 48          (0x100000, 0x10FFFD), 
 49          ] 
 50   
 51   
 52  _escapeme_re = re.compile('[%s]' % (''.join( 
 53      map(lambda (m, n): u'%s-%s' % (unichr(m), unichr(n)), 
 54          UCSCHAR + IPRIVATE)),)) 
 55   
 56   
57 -def identifierScheme(identifier):
58 """Determine if this identifier is an XRI or URI. 59 60 @returns: C{"XRI"} or C{"URI"} 61 """ 62 if identifier.startswith('xri://') or identifier[0] in XRI_AUTHORITIES: 63 return "XRI" 64 else: 65 return "URI"
66 67
68 -def toIRINormal(xri):
69 """Transform an XRI to IRI-normal form.""" 70 if not xri.startswith('xri://'): 71 xri = 'xri://' + xri 72 return escapeForIRI(xri)
73 74 75 _xref_re = re.compile('\((.*?)\)') 76 77
78 -def _escape_xref(xref_match):
79 """Escape things that need to be escaped if they're in a cross-reference. 80 """ 81 xref = xref_match.group() 82 xref = xref.replace('/', '%2F') 83 xref = xref.replace('?', '%3F') 84 xref = xref.replace('#', '%23') 85 return xref
86 87
88 -def escapeForIRI(xri):
89 """Escape things that need to be escaped when transforming to an IRI.""" 90 xri = xri.replace('%', '%25') 91 xri = _xref_re.sub(_escape_xref, xri) 92 return xri
93 94
95 -def toURINormal(xri):
96 """Transform an XRI to URI normal form.""" 97 return iriToURI(toIRINormal(xri))
98 99
100 -def _percentEscapeUnicode(char_match):
101 c = char_match.group() 102 return ''.join(['%%%X' % (ord(octet),) for octet in c.encode('utf-8')])
103 104
105 -def iriToURI(iri):
106 """Transform an IRI to a URI by escaping unicode.""" 107 # According to RFC 3987, section 3.1, "Mapping of IRIs to URIs" 108 return _escapeme_re.sub(_percentEscapeUnicode, iri)
109 110
111 -def providerIsAuthoritative(providerID, canonicalID):
112 """Is this provider ID authoritative for this XRI? 113 114 @returntype: bool 115 """ 116 # XXX: can't use rsplit until we require python >= 2.4. 117 lastbang = canonicalID.rindex('!') 118 parent = canonicalID[:lastbang] 119 return parent == providerID
120 121
122 -def rootAuthority(xri):
123 """Return the root authority for an XRI. 124 125 Example:: 126 127 rootAuthority("xri://@example") == "xri://@" 128 129 @type xri: unicode 130 @returntype: unicode 131 """ 132 if xri.startswith('xri://'): 133 xri = xri[6:] 134 authority = xri.split('/', 1)[0] 135 if authority[0] == '(': 136 # Cross-reference. 137 # XXX: This is incorrect if someone nests cross-references so there 138 # is another close-paren in there. Hopefully nobody does that 139 # before we have a real xriparse function. Hopefully nobody does 140 # that *ever*. 141 root = authority[:authority.index(')') + 1] 142 elif authority[0] in XRI_AUTHORITIES: 143 # Other XRI reference. 144 root = authority[0] 145 else: 146 # IRI reference. XXX: Can IRI authorities have segments? 147 segments = authority.split('!') 148 segments = reduce(list.__add__, 149 map(lambda s: s.split('*'), segments)) 150 root = segments[0] 151 152 return XRI(root)
153 154
155 -def XRI(xri):
156 """An XRI object allowing comparison of XRI. 157 158 Ideally, this would do full normalization and provide comparsion 159 operators as per XRI Syntax. Right now, it just does a bit of 160 canonicalization by ensuring the xri scheme is present. 161 162 @param xri: an xri string 163 @type xri: unicode 164 """ 165 if not xri.startswith('xri://'): 166 xri = 'xri://' + xri 167 return xri
168