crate 1.0.1__tar.gz → 2.0.0__tar.gz
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-1.0.1 → crate-2.0.0}/CHANGES.rst +20 -0
- {crate-1.0.1 → crate-2.0.0}/DEVELOP.rst +9 -12
- {crate-1.0.1 → crate-2.0.0}/PKG-INFO +19 -6
- {crate-1.0.1 → crate-2.0.0}/docs/by-example/http.rst +1 -1
- {crate-1.0.1 → crate-2.0.0}/pyproject.toml +7 -0
- {crate-1.0.1 → crate-2.0.0}/setup.py +4 -4
- {crate-1.0.1 → crate-2.0.0}/src/crate/client/__init__.py +1 -1
- {crate-1.0.1 → crate-2.0.0}/src/crate/client/http.py +55 -27
- {crate-1.0.1 → crate-2.0.0}/src/crate.egg-info/PKG-INFO +19 -6
- {crate-1.0.1 → crate-2.0.0}/src/crate.egg-info/requires.txt +4 -4
- {crate-1.0.1 → crate-2.0.0}/CONTRIBUTING.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/LICENSE +0 -0
- {crate-1.0.1 → crate-2.0.0}/MANIFEST.in +0 -0
- {crate-1.0.1 → crate-2.0.0}/NOTICE +0 -0
- {crate-1.0.1 → crate-2.0.0}/README.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/_extra/robots.txt +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/blobs.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/by-example/blob.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/by-example/client.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/by-example/connection.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/by-example/cursor.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/by-example/https.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/by-example/index.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/conf.py +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/connect.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/data-types.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/docutils.conf +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/getting-started.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/index-all.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/index.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/other-options.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/query.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/requirements.txt +0 -0
- {crate-1.0.1 → crate-2.0.0}/docs/sqlalchemy.rst +0 -0
- {crate-1.0.1 → crate-2.0.0}/requirements.txt +0 -0
- {crate-1.0.1 → crate-2.0.0}/setup.cfg +0 -0
- {crate-1.0.1 → crate-2.0.0}/src/crate/client/_pep440.py +0 -0
- {crate-1.0.1 → crate-2.0.0}/src/crate/client/blob.py +0 -0
- {crate-1.0.1 → crate-2.0.0}/src/crate/client/connection.py +0 -0
- {crate-1.0.1 → crate-2.0.0}/src/crate/client/converter.py +0 -0
- {crate-1.0.1 → crate-2.0.0}/src/crate/client/cursor.py +0 -0
- {crate-1.0.1 → crate-2.0.0}/src/crate/client/exceptions.py +0 -0
- {crate-1.0.1 → crate-2.0.0}/src/crate/testing/__init__.py +0 -0
- {crate-1.0.1 → crate-2.0.0}/src/crate/testing/layer.py +0 -0
- {crate-1.0.1 → crate-2.0.0}/src/crate/testing/util.py +0 -0
- {crate-1.0.1 → crate-2.0.0}/src/crate.egg-info/SOURCES.txt +0 -0
- {crate-1.0.1 → crate-2.0.0}/src/crate.egg-info/dependency_links.txt +0 -0
- {crate-1.0.1 → crate-2.0.0}/src/crate.egg-info/top_level.txt +0 -0
@@ -5,6 +5,26 @@ Changes for crate
|
|
5
5
|
Unreleased
|
6
6
|
==========
|
7
7
|
|
8
|
+
2025/01/30 2.0.0
|
9
|
+
================
|
10
|
+
|
11
|
+
- Switched JSON encoder to use the `orjson`_ library, to improve JSON
|
12
|
+
marshalling performance. Thanks, @widmogrod.
|
13
|
+
|
14
|
+
orjson is fast and in some spots even more correct when compared against
|
15
|
+
Python's stdlib ``json`` module. Contrary to the stdlib variant, orjson
|
16
|
+
will serialize to ``bytes`` instead of ``str``. When sending data to CrateDB,
|
17
|
+
``crate-python`` uses a custom encoder to add support for additional data
|
18
|
+
types.
|
19
|
+
|
20
|
+
- Python's ``Decimal`` type will be serialized to ``str``.
|
21
|
+
- Python's ``dt.datetime`` and ``dt.date`` types will be serialized to
|
22
|
+
``int`` (``LONG``) after converting to milliseconds since epoch, to
|
23
|
+
optimally accommodate CrateDB's `TIMESTAMP`_ representation.
|
24
|
+
- NumPy's data types will be handled by ``orjson`` without any ado.
|
25
|
+
|
26
|
+
.. _orjson: https://github.com/ijl/orjson
|
27
|
+
.. _TIMESTAMP: https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#type-timestamp
|
8
28
|
|
9
29
|
2024/11/23 1.0.1
|
10
30
|
================
|
@@ -5,7 +5,7 @@ CrateDB Python developer guide
|
|
5
5
|
Setup
|
6
6
|
=====
|
7
7
|
|
8
|
-
Optionally install Python package and project manager
|
8
|
+
Optionally install Python package and project manager `uv`_,
|
9
9
|
in order to significantly speed up the package installation::
|
10
10
|
|
11
11
|
{apt,brew,pip,zypper} install uv
|
@@ -67,16 +67,11 @@ To inspect the whole list of test cases, run::
|
|
67
67
|
|
68
68
|
bin/test --list-tests
|
69
69
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
on your ``$PATH``.
|
76
|
-
|
77
|
-
To run against a single interpreter, you can also invoke::
|
78
|
-
|
79
|
-
tox -e py37
|
70
|
+
The CI setup on GitHub Actions (GHA) provides a full test matrix covering
|
71
|
+
relevant Python versions. You can invoke the software tests against a specific
|
72
|
+
Python interpreter or multiple `Python versions`_ on your workstation using
|
73
|
+
`uv`_, by supplying the ``--python`` command-line option, or by defining the
|
74
|
+
`UV_PYTHON`_ environment variable prior to invoking ``source bootstrap.sh``.
|
80
75
|
|
81
76
|
*Note*: Before running the tests, make sure to stop all CrateDB instances which
|
82
77
|
are listening on the default CrateDB transport port to avoid side effects with
|
@@ -168,12 +163,14 @@ nothing special you need to do to get the live docs to update.
|
|
168
163
|
.. _@crate/docs: https://github.com/orgs/crate/teams/docs
|
169
164
|
.. _buildout: https://pypi.python.org/pypi/zc.buildout
|
170
165
|
.. _PyPI: https://pypi.python.org/pypi
|
166
|
+
.. _Python versions: https://docs.astral.sh/uv/concepts/python-versions/
|
171
167
|
.. _Read the Docs: http://readthedocs.org
|
172
168
|
.. _ReStructuredText: http://docutils.sourceforge.net/rst.html
|
173
169
|
.. _Sphinx: http://sphinx-doc.org/
|
174
170
|
.. _tests/assets/pki/*.pem: https://github.com/crate/crate-python/tree/main/tests/assets/pki
|
175
|
-
.. _tox: http://testrun.org/tox/latest/
|
176
171
|
.. _twine: https://pypi.python.org/pypi/twine
|
177
172
|
.. _useful command-line options for zope-testrunner: https://pypi.org/project/zope.testrunner/#some-useful-command-line-options-to-get-you-started
|
173
|
+
.. _uv: https://docs.astral.sh/uv/
|
174
|
+
.. _UV_PYTHON: https://docs.astral.sh/uv/configuration/environment/#uv_python
|
178
175
|
.. _versions hosted on ReadTheDocs: https://readthedocs.org/projects/crate-python/versions/
|
179
176
|
.. _zope.testrunner: https://pypi.org/project/zope.testrunner/
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: crate
|
3
|
-
Version:
|
3
|
+
Version: 2.0.0
|
4
4
|
Summary: CrateDB Python Client
|
5
5
|
Home-page: https://github.com/crate/crate-python
|
6
6
|
Author: Crate.io
|
@@ -29,6 +29,7 @@ Requires-Python: >=3.6
|
|
29
29
|
Description-Content-Type: text/x-rst
|
30
30
|
License-File: LICENSE
|
31
31
|
License-File: NOTICE
|
32
|
+
Requires-Dist: orjson<4
|
32
33
|
Requires-Dist: urllib3
|
33
34
|
Requires-Dist: verlib2
|
34
35
|
Provides-Extra: doc
|
@@ -38,15 +39,27 @@ Provides-Extra: test
|
|
38
39
|
Requires-Dist: backports.zoneinfo<1; python_version < "3.9" and extra == "test"
|
39
40
|
Requires-Dist: certifi; extra == "test"
|
40
41
|
Requires-Dist: createcoverage<2,>=1; extra == "test"
|
41
|
-
Requires-Dist: mypy<1.
|
42
|
-
Requires-Dist: poethepoet<0.
|
43
|
-
Requires-Dist: ruff<0.
|
42
|
+
Requires-Dist: mypy<1.15; extra == "test"
|
43
|
+
Requires-Dist: poethepoet<0.33; extra == "test"
|
44
|
+
Requires-Dist: ruff<0.10; extra == "test"
|
44
45
|
Requires-Dist: stopit<2,>=1.1.2; extra == "test"
|
45
|
-
Requires-Dist: tox<5,>=3; extra == "test"
|
46
46
|
Requires-Dist: pytz; extra == "test"
|
47
47
|
Requires-Dist: zc.customdoctests<2,>=1.0.1; extra == "test"
|
48
48
|
Requires-Dist: zope.testing<6,>=4; extra == "test"
|
49
49
|
Requires-Dist: zope.testrunner<7,>=5; extra == "test"
|
50
|
+
Dynamic: author
|
51
|
+
Dynamic: author-email
|
52
|
+
Dynamic: classifier
|
53
|
+
Dynamic: description
|
54
|
+
Dynamic: description-content-type
|
55
|
+
Dynamic: home-page
|
56
|
+
Dynamic: keywords
|
57
|
+
Dynamic: license
|
58
|
+
Dynamic: platform
|
59
|
+
Dynamic: provides-extra
|
60
|
+
Dynamic: requires-dist
|
61
|
+
Dynamic: requires-python
|
62
|
+
Dynamic: summary
|
50
63
|
|
51
64
|
=====================
|
52
65
|
CrateDB Python Client
|
@@ -228,7 +228,7 @@ When connecting to non-CrateDB servers, the HttpClient will raise a ConnectionEr
|
|
228
228
|
>>> http_client.server_infos(http_client._get_server())
|
229
229
|
Traceback (most recent call last):
|
230
230
|
...
|
231
|
-
crate.client.exceptions.ProgrammingError: Invalid server response of content-type 'text/html
|
231
|
+
crate.client.exceptions.ProgrammingError: Invalid server response of content-type 'text/html':
|
232
232
|
...
|
233
233
|
>>> http_client.close()
|
234
234
|
|
@@ -71,6 +71,13 @@ lint.per-file-ignores."tests/*" = [
|
|
71
71
|
"S106", # Possible hardcoded password assigned to argument: "password"
|
72
72
|
"S311", # Standard pseudo-random generators are not suitable for cryptographic purposes
|
73
73
|
]
|
74
|
+
lint.per-file-ignores."src/crate/client/{connection.py,http.py}" = [
|
75
|
+
"A004", # Import `ConnectionError` is shadowing a Python builtin
|
76
|
+
"A005", # Import `ConnectionError` is shadowing a Python builtin
|
77
|
+
]
|
78
|
+
lint.per-file-ignores."tests/client/test_http.py" = [
|
79
|
+
"A004", # Import `ConnectionError` is shadowing a Python builtin
|
80
|
+
]
|
74
81
|
|
75
82
|
|
76
83
|
# ===================
|
@@ -54,6 +54,7 @@ setup(
|
|
54
54
|
packages=find_namespace_packages("src"),
|
55
55
|
package_dir={"": "src"},
|
56
56
|
install_requires=[
|
57
|
+
"orjson<4",
|
57
58
|
"urllib3",
|
58
59
|
"verlib2",
|
59
60
|
],
|
@@ -66,11 +67,10 @@ setup(
|
|
66
67
|
'backports.zoneinfo<1; python_version<"3.9"',
|
67
68
|
"certifi",
|
68
69
|
"createcoverage>=1,<2",
|
69
|
-
"mypy<1.
|
70
|
-
"poethepoet<0.
|
71
|
-
"ruff<0.
|
70
|
+
"mypy<1.15",
|
71
|
+
"poethepoet<0.33",
|
72
|
+
"ruff<0.10",
|
72
73
|
"stopit>=1.1.2,<2",
|
73
|
-
"tox>=3,<5",
|
74
74
|
"pytz",
|
75
75
|
"zc.customdoctests>=1.0.1,<2",
|
76
76
|
"zope.testing>=4,<6",
|
@@ -21,22 +21,22 @@
|
|
21
21
|
|
22
22
|
|
23
23
|
import calendar
|
24
|
+
import datetime as dt
|
24
25
|
import heapq
|
25
26
|
import io
|
26
|
-
import json
|
27
27
|
import logging
|
28
28
|
import os
|
29
29
|
import re
|
30
30
|
import socket
|
31
31
|
import ssl
|
32
32
|
import threading
|
33
|
+
import typing as t
|
33
34
|
from base64 import b64encode
|
34
|
-
from datetime import date, datetime, timezone
|
35
35
|
from decimal import Decimal
|
36
36
|
from time import time
|
37
37
|
from urllib.parse import urlparse
|
38
|
-
from uuid import UUID
|
39
38
|
|
39
|
+
import orjson
|
40
40
|
import urllib3
|
41
41
|
from urllib3 import connection_from_url
|
42
42
|
from urllib3.connection import HTTPConnection
|
@@ -86,25 +86,53 @@ def super_len(o):
|
|
86
86
|
return None
|
87
87
|
|
88
88
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
89
|
+
epoch_aware = dt.datetime(1970, 1, 1, tzinfo=dt.timezone.utc)
|
90
|
+
epoch_naive = dt.datetime(1970, 1, 1)
|
91
|
+
|
92
|
+
|
93
|
+
def json_encoder(obj: t.Any) -> t.Union[int, str]:
|
94
|
+
"""
|
95
|
+
Encoder function for orjson, with additional type support.
|
96
|
+
|
97
|
+
- Python's `Decimal` type will be serialized to `str`.
|
98
|
+
- Python's `dt.datetime` and `dt.date` types will be
|
99
|
+
serialized to `int` after converting to milliseconds
|
100
|
+
since epoch.
|
101
|
+
|
102
|
+
https://github.com/ijl/orjson#default
|
103
|
+
https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#type-timestamp
|
104
|
+
"""
|
105
|
+
if isinstance(obj, Decimal):
|
106
|
+
return str(obj)
|
107
|
+
if isinstance(obj, dt.datetime):
|
108
|
+
if obj.tzinfo is not None:
|
109
|
+
delta = obj - epoch_aware
|
110
|
+
else:
|
111
|
+
delta = obj - epoch_naive
|
112
|
+
return int(
|
113
|
+
delta.microseconds / 1000.0
|
114
|
+
+ (delta.seconds + delta.days * 24 * 3600) * 1000.0
|
115
|
+
)
|
116
|
+
if isinstance(obj, dt.date):
|
117
|
+
return calendar.timegm(obj.timetuple()) * 1000
|
118
|
+
raise TypeError
|
119
|
+
|
120
|
+
|
121
|
+
def json_dumps(obj: t.Any) -> bytes:
|
122
|
+
"""
|
123
|
+
Serialize to JSON format, using `orjson`, with additional type support.
|
124
|
+
|
125
|
+
https://github.com/ijl/orjson
|
126
|
+
"""
|
127
|
+
return orjson.dumps(
|
128
|
+
obj,
|
129
|
+
default=json_encoder,
|
130
|
+
option=(
|
131
|
+
orjson.OPT_PASSTHROUGH_DATETIME
|
132
|
+
| orjson.OPT_NON_STR_KEYS
|
133
|
+
| orjson.OPT_SERIALIZE_NUMPY
|
134
|
+
),
|
135
|
+
)
|
108
136
|
|
109
137
|
|
110
138
|
class Server:
|
@@ -180,7 +208,7 @@ class Server:
|
|
180
208
|
|
181
209
|
def _json_from_response(response):
|
182
210
|
try:
|
183
|
-
return
|
211
|
+
return orjson.loads(response.data)
|
184
212
|
except ValueError as ex:
|
185
213
|
raise ProgrammingError(
|
186
214
|
"Invalid server response of content-type '{}':\n{}".format(
|
@@ -223,7 +251,7 @@ def _raise_for_status_real(response):
|
|
223
251
|
if response.status == 503:
|
224
252
|
raise ConnectionError(message)
|
225
253
|
if response.headers.get("content-type", "").startswith("application/json"):
|
226
|
-
data =
|
254
|
+
data = orjson.loads(response.data)
|
227
255
|
error = data.get("error", {})
|
228
256
|
error_trace = data.get("error_trace", None)
|
229
257
|
if "results" in data:
|
@@ -323,7 +351,7 @@ def _update_pool_kwargs_for_ssl_minimum_version(server, kwargs):
|
|
323
351
|
kwargs["ssl_minimum_version"] = ssl.TLSVersion.MINIMUM_SUPPORTED
|
324
352
|
|
325
353
|
|
326
|
-
def _create_sql_payload(stmt, args, bulk_args):
|
354
|
+
def _create_sql_payload(stmt, args, bulk_args) -> bytes:
|
327
355
|
if not isinstance(stmt, str):
|
328
356
|
raise ValueError("stmt is not a string")
|
329
357
|
if args and bulk_args:
|
@@ -334,7 +362,7 @@ def _create_sql_payload(stmt, args, bulk_args):
|
|
334
362
|
data["args"] = args
|
335
363
|
if bulk_args:
|
336
364
|
data["bulk_args"] = bulk_args
|
337
|
-
return
|
365
|
+
return json_dumps(data)
|
338
366
|
|
339
367
|
|
340
368
|
def _get_socket_opts(
|
@@ -670,7 +698,7 @@ class Client:
|
|
670
698
|
# if this is the last server raise exception, otherwise try next
|
671
699
|
if not self._active_servers:
|
672
700
|
raise ConnectionError(
|
673
|
-
("No more Servers available,
|
701
|
+
("No more Servers available, exception from last server: %s")
|
674
702
|
% message
|
675
703
|
)
|
676
704
|
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: crate
|
3
|
-
Version:
|
3
|
+
Version: 2.0.0
|
4
4
|
Summary: CrateDB Python Client
|
5
5
|
Home-page: https://github.com/crate/crate-python
|
6
6
|
Author: Crate.io
|
@@ -29,6 +29,7 @@ Requires-Python: >=3.6
|
|
29
29
|
Description-Content-Type: text/x-rst
|
30
30
|
License-File: LICENSE
|
31
31
|
License-File: NOTICE
|
32
|
+
Requires-Dist: orjson<4
|
32
33
|
Requires-Dist: urllib3
|
33
34
|
Requires-Dist: verlib2
|
34
35
|
Provides-Extra: doc
|
@@ -38,15 +39,27 @@ Provides-Extra: test
|
|
38
39
|
Requires-Dist: backports.zoneinfo<1; python_version < "3.9" and extra == "test"
|
39
40
|
Requires-Dist: certifi; extra == "test"
|
40
41
|
Requires-Dist: createcoverage<2,>=1; extra == "test"
|
41
|
-
Requires-Dist: mypy<1.
|
42
|
-
Requires-Dist: poethepoet<0.
|
43
|
-
Requires-Dist: ruff<0.
|
42
|
+
Requires-Dist: mypy<1.15; extra == "test"
|
43
|
+
Requires-Dist: poethepoet<0.33; extra == "test"
|
44
|
+
Requires-Dist: ruff<0.10; extra == "test"
|
44
45
|
Requires-Dist: stopit<2,>=1.1.2; extra == "test"
|
45
|
-
Requires-Dist: tox<5,>=3; extra == "test"
|
46
46
|
Requires-Dist: pytz; extra == "test"
|
47
47
|
Requires-Dist: zc.customdoctests<2,>=1.0.1; extra == "test"
|
48
48
|
Requires-Dist: zope.testing<6,>=4; extra == "test"
|
49
49
|
Requires-Dist: zope.testrunner<7,>=5; extra == "test"
|
50
|
+
Dynamic: author
|
51
|
+
Dynamic: author-email
|
52
|
+
Dynamic: classifier
|
53
|
+
Dynamic: description
|
54
|
+
Dynamic: description-content-type
|
55
|
+
Dynamic: home-page
|
56
|
+
Dynamic: keywords
|
57
|
+
Dynamic: license
|
58
|
+
Dynamic: platform
|
59
|
+
Dynamic: provides-extra
|
60
|
+
Dynamic: requires-dist
|
61
|
+
Dynamic: requires-python
|
62
|
+
Dynamic: summary
|
50
63
|
|
51
64
|
=====================
|
52
65
|
CrateDB Python Client
|
@@ -1,3 +1,4 @@
|
|
1
|
+
orjson<4
|
1
2
|
urllib3
|
2
3
|
verlib2
|
3
4
|
|
@@ -8,11 +9,10 @@ sphinx<9,>=3.5
|
|
8
9
|
[test]
|
9
10
|
certifi
|
10
11
|
createcoverage<2,>=1
|
11
|
-
mypy<1.
|
12
|
-
poethepoet<0.
|
13
|
-
ruff<0.
|
12
|
+
mypy<1.15
|
13
|
+
poethepoet<0.33
|
14
|
+
ruff<0.10
|
14
15
|
stopit<2,>=1.1.2
|
15
|
-
tox<5,>=3
|
16
16
|
pytz
|
17
17
|
zc.customdoctests<2,>=1.0.1
|
18
18
|
zope.testing<6,>=4
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|