crate 2.0.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crate/client/__init__.py +37 -0
- crate/client/_pep440.py +1 -0
- crate/client/blob.py +105 -0
- crate/client/connection.py +221 -0
- crate/client/converter.py +143 -0
- crate/client/cursor.py +321 -0
- crate/client/exceptions.py +101 -0
- crate/client/http.py +694 -0
- crate/testing/__init__.py +0 -0
- crate/testing/layer.py +428 -0
- crate/testing/util.py +95 -0
- crate-2.0.0.dev0.dist-info/LICENSE +178 -0
- crate-2.0.0.dev0.dist-info/METADATA +168 -0
- crate-2.0.0.dev0.dist-info/NOTICE +24 -0
- crate-2.0.0.dev0.dist-info/RECORD +17 -0
- crate-2.0.0.dev0.dist-info/WHEEL +5 -0
- crate-2.0.0.dev0.dist-info/top_level.txt +1 -0
crate/client/__init__.py
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- coding: utf-8; -*-
|
2
|
+
#
|
3
|
+
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
|
+
# license agreements. See the NOTICE file distributed with this work for
|
5
|
+
# additional information regarding copyright ownership. Crate licenses
|
6
|
+
# this file to you under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License. You may
|
8
|
+
# obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
#
|
18
|
+
# However, if you have executed another commercial license agreement
|
19
|
+
# with Crate these terms will supersede the license and you may use the
|
20
|
+
# software solely pursuant to the terms of the relevant commercial agreement.
|
21
|
+
|
22
|
+
from .connection import Connection as connect
|
23
|
+
from .exceptions import Error
|
24
|
+
|
25
|
+
__all__ = [
|
26
|
+
"connect",
|
27
|
+
"Error",
|
28
|
+
]
|
29
|
+
|
30
|
+
# version string read from setup.py using a regex. Take care not to break the
|
31
|
+
# regex!
|
32
|
+
__version__ = "2.0.0.dev0"
|
33
|
+
|
34
|
+
# codeql[py/unused-global-variable]
|
35
|
+
apilevel = "2.0"
|
36
|
+
threadsafety = 1
|
37
|
+
paramstyle = "qmark"
|
crate/client/_pep440.py
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
from verlib2 import Version # noqa: F401
|
crate/client/blob.py
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# -*- coding: utf-8; -*-
|
2
|
+
#
|
3
|
+
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
|
+
# license agreements. See the NOTICE file distributed with this work for
|
5
|
+
# additional information regarding copyright ownership. Crate licenses
|
6
|
+
# this file to you under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License. You may
|
8
|
+
# obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
#
|
18
|
+
# However, if you have executed another commercial license agreement
|
19
|
+
# with Crate these terms will supersede the license and you may use the
|
20
|
+
# software solely pursuant to the terms of the relevant commercial agreement.
|
21
|
+
|
22
|
+
import hashlib
|
23
|
+
|
24
|
+
|
25
|
+
class BlobContainer:
|
26
|
+
"""class that represents a blob collection in crate.
|
27
|
+
|
28
|
+
can be used to download, upload and delete blobs
|
29
|
+
"""
|
30
|
+
|
31
|
+
def __init__(self, container_name, connection):
|
32
|
+
self.container_name = container_name
|
33
|
+
self.conn = connection
|
34
|
+
|
35
|
+
def _compute_digest(self, f):
|
36
|
+
f.seek(0)
|
37
|
+
m = hashlib.sha1() # noqa: S324
|
38
|
+
while True:
|
39
|
+
d = f.read(1024 * 32)
|
40
|
+
if not d:
|
41
|
+
break
|
42
|
+
m.update(d)
|
43
|
+
f.seek(0)
|
44
|
+
return m.hexdigest()
|
45
|
+
|
46
|
+
def put(self, f, digest=None):
|
47
|
+
"""
|
48
|
+
Upload a blob
|
49
|
+
|
50
|
+
:param f:
|
51
|
+
File object to be uploaded (required to support seek if digest is
|
52
|
+
not provided).
|
53
|
+
:param digest:
|
54
|
+
Optional SHA-1 hex digest of the file contents. Gets computed
|
55
|
+
before actual upload if not provided, which requires an extra file
|
56
|
+
read.
|
57
|
+
:return:
|
58
|
+
The hex digest of the uploaded blob if not provided in the call.
|
59
|
+
Otherwise a boolean indicating if the blob has been newly created.
|
60
|
+
"""
|
61
|
+
|
62
|
+
if digest:
|
63
|
+
actual_digest = digest
|
64
|
+
else:
|
65
|
+
actual_digest = self._compute_digest(f)
|
66
|
+
|
67
|
+
created = self.conn.client.blob_put(
|
68
|
+
self.container_name, actual_digest, f
|
69
|
+
)
|
70
|
+
if digest:
|
71
|
+
return created
|
72
|
+
return actual_digest
|
73
|
+
|
74
|
+
def get(self, digest, chunk_size=1024 * 128):
|
75
|
+
"""
|
76
|
+
Return the contents of a blob
|
77
|
+
|
78
|
+
:param digest: the hex digest of the blob to return
|
79
|
+
:param chunk_size: the size of the chunks returned on each iteration
|
80
|
+
:return: generator returning chunks of data
|
81
|
+
"""
|
82
|
+
return self.conn.client.blob_get(
|
83
|
+
self.container_name, digest, chunk_size
|
84
|
+
)
|
85
|
+
|
86
|
+
def delete(self, digest):
|
87
|
+
"""
|
88
|
+
Delete a blob
|
89
|
+
|
90
|
+
:param digest: the hex digest of the blob to be deleted
|
91
|
+
:return: True if blob existed
|
92
|
+
"""
|
93
|
+
return self.conn.client.blob_del(self.container_name, digest)
|
94
|
+
|
95
|
+
def exists(self, digest):
|
96
|
+
"""
|
97
|
+
Check if a blob exists
|
98
|
+
|
99
|
+
:param digest: Hex digest of the blob
|
100
|
+
:return: Boolean indicating existence of the blob
|
101
|
+
"""
|
102
|
+
return self.conn.client.blob_exists(self.container_name, digest)
|
103
|
+
|
104
|
+
def __repr__(self):
|
105
|
+
return "<BlobContainer '{0}'>".format(self.container_name)
|
@@ -0,0 +1,221 @@
|
|
1
|
+
# -*- coding: utf-8; -*-
|
2
|
+
#
|
3
|
+
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
|
+
# license agreements. See the NOTICE file distributed with this work for
|
5
|
+
# additional information regarding copyright ownership. Crate licenses
|
6
|
+
# this file to you under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License. You may
|
8
|
+
# obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
#
|
18
|
+
# However, if you have executed another commercial license agreement
|
19
|
+
# with Crate these terms will supersede the license and you may use the
|
20
|
+
# software solely pursuant to the terms of the relevant commercial agreement.
|
21
|
+
|
22
|
+
from verlib2 import Version
|
23
|
+
|
24
|
+
from .blob import BlobContainer
|
25
|
+
from .cursor import Cursor
|
26
|
+
from .exceptions import ConnectionError, ProgrammingError
|
27
|
+
from .http import Client
|
28
|
+
|
29
|
+
|
30
|
+
class Connection:
|
31
|
+
def __init__(
|
32
|
+
self,
|
33
|
+
servers=None,
|
34
|
+
timeout=None,
|
35
|
+
backoff_factor=0,
|
36
|
+
client=None,
|
37
|
+
verify_ssl_cert=True,
|
38
|
+
ca_cert=None,
|
39
|
+
error_trace=False,
|
40
|
+
cert_file=None,
|
41
|
+
key_file=None,
|
42
|
+
ssl_relax_minimum_version=False,
|
43
|
+
username=None,
|
44
|
+
password=None,
|
45
|
+
schema=None,
|
46
|
+
pool_size=None,
|
47
|
+
socket_keepalive=True,
|
48
|
+
socket_tcp_keepidle=None,
|
49
|
+
socket_tcp_keepintvl=None,
|
50
|
+
socket_tcp_keepcnt=None,
|
51
|
+
converter=None,
|
52
|
+
time_zone=None,
|
53
|
+
):
|
54
|
+
"""
|
55
|
+
:param servers:
|
56
|
+
either a string in the form of '<hostname>:<port>'
|
57
|
+
or a list of servers in the form of ['<hostname>:<port>', '...']
|
58
|
+
:param timeout:
|
59
|
+
(optional)
|
60
|
+
define the retry timeout for unreachable servers in seconds
|
61
|
+
:param backoff_factor:
|
62
|
+
(optional)
|
63
|
+
define the retry interval for unreachable servers in seconds
|
64
|
+
:param client:
|
65
|
+
(optional - for testing)
|
66
|
+
client used to communicate with crate.
|
67
|
+
:param verify_ssl_cert:
|
68
|
+
if set to ``False``, disable SSL server certificate verification.
|
69
|
+
defaults to ``True``
|
70
|
+
:param ca_cert:
|
71
|
+
a path to a CA certificate to use when verifying the SSL server
|
72
|
+
certificate.
|
73
|
+
:param error_trace:
|
74
|
+
if set to ``True`` return a whole stacktrace of any server error if
|
75
|
+
one occurs
|
76
|
+
:param cert_file:
|
77
|
+
a path to the client certificate to present to the server.
|
78
|
+
:param key_file:
|
79
|
+
a path to the client key to use when communicating with the server.
|
80
|
+
:param username:
|
81
|
+
the username in the database.
|
82
|
+
:param password:
|
83
|
+
the password of the user in the database.
|
84
|
+
:param pool_size:
|
85
|
+
(optional)
|
86
|
+
Number of connections to save that can be reused.
|
87
|
+
More than 1 is useful in multithreaded situations.
|
88
|
+
:param socket_keepalive:
|
89
|
+
(optional, defaults to ``True``)
|
90
|
+
Enable TCP keepalive on socket level.
|
91
|
+
:param socket_tcp_keepidle:
|
92
|
+
(optional)
|
93
|
+
Set the ``TCP_KEEPIDLE`` socket option, which overrides
|
94
|
+
``net.ipv4.tcp_keepalive_time`` kernel setting if ``socket_keepalive``
|
95
|
+
is ``True``.
|
96
|
+
:param socket_tcp_keepintvl:
|
97
|
+
(optional)
|
98
|
+
Set the ``TCP_KEEPINTVL`` socket option, which overrides
|
99
|
+
``net.ipv4.tcp_keepalive_intvl`` kernel setting if ``socket_keepalive``
|
100
|
+
is ``True``.
|
101
|
+
:param socket_tcp_keepcnt:
|
102
|
+
(optional)
|
103
|
+
Set the ``TCP_KEEPCNT`` socket option, which overrides
|
104
|
+
``net.ipv4.tcp_keepalive_probes`` kernel setting if ``socket_keepalive``
|
105
|
+
is ``True``.
|
106
|
+
:param converter:
|
107
|
+
(optional, defaults to ``None``)
|
108
|
+
A `Converter` object to propagate to newly created `Cursor` objects.
|
109
|
+
:param time_zone:
|
110
|
+
(optional, defaults to ``None``)
|
111
|
+
A time zone specifier used for returning `TIMESTAMP` types as
|
112
|
+
timezone-aware native Python `datetime` objects.
|
113
|
+
|
114
|
+
Different data types are supported. Available options are:
|
115
|
+
|
116
|
+
- ``datetime.timezone.utc``
|
117
|
+
- ``datetime.timezone(datetime.timedelta(hours=7), name="MST")``
|
118
|
+
- ``pytz.timezone("Australia/Sydney")``
|
119
|
+
- ``zoneinfo.ZoneInfo("Australia/Sydney")``
|
120
|
+
- ``+0530`` (UTC offset in string format)
|
121
|
+
|
122
|
+
The driver always returns timezone-"aware" `datetime` objects,
|
123
|
+
with their `tzinfo` attribute set.
|
124
|
+
|
125
|
+
When `time_zone` is `None`, the returned `datetime` objects are
|
126
|
+
using Coordinated Universal Time (UTC), because CrateDB is storing
|
127
|
+
timestamp values in this format.
|
128
|
+
|
129
|
+
When `time_zone` is given, the timestamp values will be transparently
|
130
|
+
converted from UTC to use the given time zone.
|
131
|
+
""" # noqa: E501
|
132
|
+
|
133
|
+
self._converter = converter
|
134
|
+
self.time_zone = time_zone
|
135
|
+
|
136
|
+
if client:
|
137
|
+
self.client = client
|
138
|
+
else:
|
139
|
+
self.client = Client(
|
140
|
+
servers,
|
141
|
+
timeout=timeout,
|
142
|
+
backoff_factor=backoff_factor,
|
143
|
+
verify_ssl_cert=verify_ssl_cert,
|
144
|
+
ca_cert=ca_cert,
|
145
|
+
error_trace=error_trace,
|
146
|
+
cert_file=cert_file,
|
147
|
+
key_file=key_file,
|
148
|
+
ssl_relax_minimum_version=ssl_relax_minimum_version,
|
149
|
+
username=username,
|
150
|
+
password=password,
|
151
|
+
schema=schema,
|
152
|
+
pool_size=pool_size,
|
153
|
+
socket_keepalive=socket_keepalive,
|
154
|
+
socket_tcp_keepidle=socket_tcp_keepidle,
|
155
|
+
socket_tcp_keepintvl=socket_tcp_keepintvl,
|
156
|
+
socket_tcp_keepcnt=socket_tcp_keepcnt,
|
157
|
+
)
|
158
|
+
self.lowest_server_version = self._lowest_server_version()
|
159
|
+
self._closed = False
|
160
|
+
|
161
|
+
def cursor(self, **kwargs) -> Cursor:
|
162
|
+
"""
|
163
|
+
Return a new Cursor Object using the connection.
|
164
|
+
"""
|
165
|
+
converter = kwargs.pop("converter", self._converter)
|
166
|
+
time_zone = kwargs.pop("time_zone", self.time_zone)
|
167
|
+
if not self._closed:
|
168
|
+
return Cursor(
|
169
|
+
connection=self,
|
170
|
+
converter=converter,
|
171
|
+
time_zone=time_zone,
|
172
|
+
)
|
173
|
+
else:
|
174
|
+
raise ProgrammingError("Connection closed")
|
175
|
+
|
176
|
+
def close(self):
|
177
|
+
"""
|
178
|
+
Close the connection now
|
179
|
+
"""
|
180
|
+
self._closed = True
|
181
|
+
self.client.close()
|
182
|
+
|
183
|
+
def commit(self):
|
184
|
+
"""
|
185
|
+
Transactions are not supported, so ``commit`` is not implemented.
|
186
|
+
"""
|
187
|
+
if self._closed:
|
188
|
+
raise ProgrammingError("Connection closed")
|
189
|
+
|
190
|
+
def get_blob_container(self, container_name):
|
191
|
+
"""Retrieve a BlobContainer for `container_name`
|
192
|
+
|
193
|
+
:param container_name: the name of the BLOB container.
|
194
|
+
:returns: a :class:ContainerObject
|
195
|
+
"""
|
196
|
+
return BlobContainer(container_name, self)
|
197
|
+
|
198
|
+
def _lowest_server_version(self):
|
199
|
+
lowest = None
|
200
|
+
for server in self.client.active_servers:
|
201
|
+
try:
|
202
|
+
_, _, version = self.client.server_infos(server)
|
203
|
+
version = Version(version)
|
204
|
+
except (ValueError, ConnectionError):
|
205
|
+
continue
|
206
|
+
if not lowest or version < lowest:
|
207
|
+
lowest = version
|
208
|
+
return lowest or Version("0.0.0")
|
209
|
+
|
210
|
+
def __repr__(self):
|
211
|
+
return "<Connection {0}>".format(repr(self.client))
|
212
|
+
|
213
|
+
def __enter__(self):
|
214
|
+
return self
|
215
|
+
|
216
|
+
def __exit__(self, *excs):
|
217
|
+
self.close()
|
218
|
+
|
219
|
+
|
220
|
+
# For backwards compatibility and not to break existing imports
|
221
|
+
connect = Connection
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# -*- coding: utf-8; -*-
|
2
|
+
#
|
3
|
+
# Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
|
4
|
+
# license agreements. See the NOTICE file distributed with this work for
|
5
|
+
# additional information regarding copyright ownership. Crate licenses
|
6
|
+
# this file to you under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License. You may
|
8
|
+
# obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
#
|
18
|
+
# However, if you have executed another commercial license agreement
|
19
|
+
# with Crate these terms will supersede the license and you may use the
|
20
|
+
# software solely pursuant to the terms of the relevant commercial agreement.
|
21
|
+
"""
|
22
|
+
Machinery for converting CrateDB database types to native Python data types.
|
23
|
+
|
24
|
+
https://crate.io/docs/crate/reference/en/latest/interfaces/http.html#column-types
|
25
|
+
"""
|
26
|
+
|
27
|
+
import datetime as dt
|
28
|
+
import ipaddress
|
29
|
+
from copy import deepcopy
|
30
|
+
from enum import Enum
|
31
|
+
from typing import Any, Callable, Dict, List, Optional, Union
|
32
|
+
|
33
|
+
ConverterFunction = Callable[[Optional[Any]], Optional[Any]]
|
34
|
+
ColTypesDefinition = Union[int, List[Union[int, "ColTypesDefinition"]]]
|
35
|
+
|
36
|
+
|
37
|
+
def _to_ipaddress(
|
38
|
+
value: Optional[str],
|
39
|
+
) -> Optional[Union[ipaddress.IPv4Address, ipaddress.IPv6Address]]:
|
40
|
+
"""
|
41
|
+
https://docs.python.org/3/library/ipaddress.html
|
42
|
+
"""
|
43
|
+
if value is None:
|
44
|
+
return None
|
45
|
+
return ipaddress.ip_address(value)
|
46
|
+
|
47
|
+
|
48
|
+
def _to_datetime(value: Optional[float]) -> Optional[dt.datetime]:
|
49
|
+
"""
|
50
|
+
https://docs.python.org/3/library/datetime.html
|
51
|
+
"""
|
52
|
+
if value is None:
|
53
|
+
return None
|
54
|
+
return dt.datetime.fromtimestamp(value / 1e3, tz=dt.timezone.utc)
|
55
|
+
|
56
|
+
|
57
|
+
def _to_default(value: Optional[Any]) -> Optional[Any]:
|
58
|
+
return value
|
59
|
+
|
60
|
+
|
61
|
+
# Data type identifiers defined by the CrateDB HTTP interface.
|
62
|
+
# https://crate.io/docs/crate/reference/en/latest/interfaces/http.html#column-types
|
63
|
+
class DataType(Enum):
|
64
|
+
NULL = 0
|
65
|
+
NOT_SUPPORTED = 1
|
66
|
+
CHAR = 2
|
67
|
+
BOOLEAN = 3
|
68
|
+
TEXT = 4
|
69
|
+
IP = 5
|
70
|
+
DOUBLE = 6
|
71
|
+
REAL = 7
|
72
|
+
SMALLINT = 8
|
73
|
+
INTEGER = 9
|
74
|
+
BIGINT = 10
|
75
|
+
TIMESTAMP_WITH_TZ = 11
|
76
|
+
OBJECT = 12
|
77
|
+
GEOPOINT = 13
|
78
|
+
GEOSHAPE = 14
|
79
|
+
TIMESTAMP_WITHOUT_TZ = 15
|
80
|
+
UNCHECKED_OBJECT = 16
|
81
|
+
REGPROC = 19
|
82
|
+
TIME = 20
|
83
|
+
OIDVECTOR = 21
|
84
|
+
NUMERIC = 22
|
85
|
+
REGCLASS = 23
|
86
|
+
DATE = 24
|
87
|
+
BIT = 25
|
88
|
+
JSON = 26
|
89
|
+
CHARACTER = 27
|
90
|
+
ARRAY = 100
|
91
|
+
|
92
|
+
|
93
|
+
ConverterMapping = Dict[DataType, ConverterFunction]
|
94
|
+
|
95
|
+
|
96
|
+
# Map data type identifier to converter function.
|
97
|
+
_DEFAULT_CONVERTERS: ConverterMapping = {
|
98
|
+
DataType.IP: _to_ipaddress,
|
99
|
+
DataType.TIMESTAMP_WITH_TZ: _to_datetime,
|
100
|
+
DataType.TIMESTAMP_WITHOUT_TZ: _to_datetime,
|
101
|
+
}
|
102
|
+
|
103
|
+
|
104
|
+
class Converter:
|
105
|
+
def __init__(
|
106
|
+
self,
|
107
|
+
mappings: Optional[ConverterMapping] = None,
|
108
|
+
default: ConverterFunction = _to_default,
|
109
|
+
) -> None:
|
110
|
+
self._mappings = mappings or {}
|
111
|
+
self._default = default
|
112
|
+
|
113
|
+
def get(self, type_: ColTypesDefinition) -> ConverterFunction:
|
114
|
+
if isinstance(type_, int):
|
115
|
+
return self._mappings.get(DataType(type_), self._default)
|
116
|
+
type_, inner_type = type_
|
117
|
+
if DataType(type_) is not DataType.ARRAY:
|
118
|
+
raise ValueError(
|
119
|
+
f"Data type {type_} is not implemented as collection type"
|
120
|
+
)
|
121
|
+
|
122
|
+
inner_convert = self.get(inner_type)
|
123
|
+
|
124
|
+
def convert(value: Any) -> Optional[List[Any]]:
|
125
|
+
if value is None:
|
126
|
+
return None
|
127
|
+
return [inner_convert(x) for x in value]
|
128
|
+
|
129
|
+
return convert
|
130
|
+
|
131
|
+
def set(self, type_: DataType, converter: ConverterFunction):
|
132
|
+
self._mappings[type_] = converter
|
133
|
+
|
134
|
+
|
135
|
+
class DefaultTypeConverter(Converter):
|
136
|
+
def __init__(
|
137
|
+
self, more_mappings: Optional[ConverterMapping] = None
|
138
|
+
) -> None:
|
139
|
+
mappings: ConverterMapping = {}
|
140
|
+
mappings.update(deepcopy(_DEFAULT_CONVERTERS))
|
141
|
+
if more_mappings:
|
142
|
+
mappings.update(deepcopy(more_mappings))
|
143
|
+
super().__init__(mappings=mappings, default=_to_default)
|