1"""Tools for parsing."""
2
3from __future__ import annotations
4
5SEQUENCE_TYPES = (list, tuple)
6DEFAULT_ENCODING = "utf-8"
7ICAL_TYPE = str | bytes
8
9
10def from_unicode(value: ICAL_TYPE, encoding: str = "utf-8") -> bytes:
11 """Converts a value to bytes, even if it is already bytes.
12
13 Parameters:
14 value: The value to convert.
15 encoding: The encoding to use in the conversion.
16
17 Returns:
18 The bytes representation of the value.
19 """
20 if isinstance(value, bytes):
21 return value
22 if isinstance(value, str):
23 try:
24 return value.encode(encoding)
25 except UnicodeEncodeError:
26 return value.encode("utf-8", "replace")
27 else:
28 return value
29
30
31def to_unicode(value: ICAL_TYPE, encoding: str = "utf-8-sig") -> str:
32 """Converts a value to Unicode, even if it is already a Unicode string.
33
34 Parameters:
35 value: The value to convert.
36 encoding: The encoding to use in the conversion.
37 """
38 if isinstance(value, str):
39 return value
40 if isinstance(value, bytes):
41 try:
42 return value.decode(encoding)
43 except UnicodeDecodeError:
44 return value.decode("utf-8-sig", "replace")
45 else:
46 return value
47
48
49def data_encode(
50 data: ICAL_TYPE | dict | list, encoding: str = DEFAULT_ENCODING
51) -> bytes | list[bytes] | dict:
52 """Encode all datastructures to the given encoding.
53
54 Currently Unicode strings, dicts, and lists are supported.
55
56 Parameters:
57 data: The datastructure to encode.
58 """
59 # https://stackoverflow.com/questions/1254454/fastest-way-to-convert-a-dicts-keys-values-from-unicode-to-str
60 if isinstance(data, str):
61 return data.encode(encoding)
62 if isinstance(data, dict):
63 return dict(map(data_encode, iter(data.items())))
64 if isinstance(data, (list, tuple)):
65 return list(map(data_encode, data))
66 return data
67
68
69__all__ = [
70 "DEFAULT_ENCODING",
71 "ICAL_TYPE",
72 "SEQUENCE_TYPES",
73 "data_encode",
74 "from_unicode",
75 "to_unicode",
76]