1import base64
2import unicodedata
3from binascii import Error as BinasciiError
4
5
6def urlsafe_base64_encode(s: bytes) -> str:
7 """
8 Encode a bytestring to a base64 string for use in URLs. Strip any trailing
9 equal signs.
10 """
11 return base64.urlsafe_b64encode(s).rstrip(b"\n=").decode("ascii")
12
13
14def urlsafe_base64_decode(s: str) -> bytes:
15 """
16 Decode a base64 encoded string. Add back any trailing equal signs that
17 might have been stripped.
18 """
19 s_bytes = s.encode()
20 try:
21 return base64.urlsafe_b64decode(
22 s_bytes.ljust(len(s_bytes) + len(s_bytes) % 4, b"=")
23 )
24 except (LookupError, BinasciiError) as e:
25 raise ValueError(e)
26
27
28def unicode_ci_compare(s1: str, s2: str) -> bool:
29 """
30 Perform case-insensitive comparison of two identifiers, using the
31 recommended algorithm from Unicode Technical Report 36, section
32 2.11.2(B)(2).
33 """
34 return (
35 unicodedata.normalize("NFKC", s1).casefold()
36 == unicodedata.normalize("NFKC", s2).casefold()
37 )