Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/azure/core/utils/_utils.py: 32%
71 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-07 06:33 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-07 06:33 +0000
1# coding=utf-8
2# --------------------------------------------------------------------------
3# Copyright (c) Microsoft Corporation. All rights reserved.
4# Licensed under the MIT License. See License.txt in the project root for
5# license information.
6# --------------------------------------------------------------------------
7import datetime
8from typing import (
9 Any,
10 Iterable,
11 Iterator,
12 Mapping,
13 MutableMapping,
14 Optional,
15 Tuple,
16 Union,
17 Dict,
18)
19from datetime import timezone
21TZ_UTC = timezone.utc
24class _FixedOffset(datetime.tzinfo):
25 """Fixed offset in minutes east from UTC.
27 Copy/pasted from Python doc
29 :param int offset: offset in minutes
30 """
32 def __init__(self, offset):
33 self.__offset = datetime.timedelta(minutes=offset)
35 def utcoffset(self, dt):
36 return self.__offset
38 def tzname(self, dt):
39 return str(self.__offset.total_seconds() / 3600)
41 def __repr__(self):
42 return "<FixedOffset {}>".format(self.tzname(None))
44 def dst(self, dt):
45 return datetime.timedelta(0)
48def _convert_to_isoformat(date_time):
49 """Deserialize a date in RFC 3339 format to datetime object.
50 Check https://tools.ietf.org/html/rfc3339#section-5.8 for examples.
52 :param str date_time: The date in RFC 3339 format.
53 """
54 if not date_time:
55 return None
56 if date_time[-1] == "Z":
57 delta = 0
58 timestamp = date_time[:-1]
59 else:
60 timestamp = date_time[:-6]
61 sign, offset = date_time[-6], date_time[-5:]
62 delta = int(sign + offset[:1]) * 60 + int(sign + offset[-2:])
64 check_decimal = timestamp.split(".")
65 if len(check_decimal) > 1:
66 decimal_str = ""
67 for digit in check_decimal[1]:
68 if digit.isdigit():
69 decimal_str += digit
70 else:
71 break
72 if len(decimal_str) > 6:
73 timestamp = timestamp.replace(decimal_str, decimal_str[0:6])
75 if delta == 0:
76 tzinfo = TZ_UTC
77 else:
78 tzinfo = timezone(datetime.timedelta(minutes=delta))
80 try:
81 deserialized = datetime.datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S.%f")
82 except ValueError:
83 deserialized = datetime.datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S")
85 deserialized = deserialized.replace(tzinfo=tzinfo)
86 return deserialized
89def case_insensitive_dict(
90 *args: Optional[Union[Mapping[str, Any], Iterable[Tuple[str, Any]]]], **kwargs: Any
91) -> MutableMapping[str, Any]:
92 """Return a case-insensitive mutable mapping from an inputted mapping structure.
94 :param args: The positional arguments to pass to the dict.
95 :type args: Mapping[str, Any] or Iterable[Tuple[str, Any]
96 :return: A case-insensitive mutable mapping object.
97 :rtype: ~collections.abc.MutableMapping
98 """
99 return CaseInsensitiveDict(*args, **kwargs)
102class CaseInsensitiveDict(MutableMapping[str, Any]):
103 """
104 NOTE: This implementation is heavily inspired from the case insensitive dictionary from the requests library.
105 Thank you !!
106 Case insensitive dictionary implementation.
107 The keys are expected to be strings and will be stored in lower case.
108 case_insensitive_dict = CaseInsensitiveDict()
109 case_insensitive_dict['Key'] = 'some_value'
110 case_insensitive_dict['key'] == 'some_value' #True
112 :param data: Initial data to store in the dictionary.
113 :type data: Mapping[str, Any] or Iterable[Tuple[str, Any]]
114 """
116 def __init__(
117 self, data: Optional[Union[Mapping[str, Any], Iterable[Tuple[str, Any]]]] = None, **kwargs: Any
118 ) -> None:
119 self._store: Dict[str, Any] = {}
120 if data is None:
121 data = {}
123 self.update(data, **kwargs)
125 def copy(self) -> "CaseInsensitiveDict":
126 return CaseInsensitiveDict(self._store.values())
128 def __setitem__(self, key: str, value: Any) -> None:
129 """Set the `key` to `value`.
131 The original key will be stored with the value
133 :param str key: The key to set.
134 :param value: The value to set the key to.
135 :type value: any
136 """
137 self._store[key.lower()] = (key, value)
139 def __getitem__(self, key: str) -> Any:
140 return self._store[key.lower()][1]
142 def __delitem__(self, key: str) -> None:
143 del self._store[key.lower()]
145 def __iter__(self) -> Iterator[str]:
146 return (key for key, _ in self._store.values())
148 def __len__(self) -> int:
149 return len(self._store)
151 def lowerkey_items(self) -> Iterator[Tuple[str, Any]]:
152 return ((lower_case_key, pair[1]) for lower_case_key, pair in self._store.items())
154 def __eq__(self, other: Any) -> bool:
155 if isinstance(other, Mapping):
156 other = CaseInsensitiveDict(other)
157 else:
158 return False
160 return dict(self.lowerkey_items()) == dict(other.lowerkey_items())
162 def __repr__(self) -> str:
163 return str(dict(self.items()))