From e7c4feae8576a34e0bbb0f8515b675e63eab3785 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 01:14:10 -0800 Subject: [PATCH 01/22] xxhash --- awscrt/checksums.py | 60 +++++++++++ crt/aws-checksums | 2 +- source/checksums.h | 9 ++ source/module.c | 10 ++ source/xxhash.c | 230 +++++++++++++++++++++++++++++++++++++++++ test/test_checksums.py | 46 +++++++++ 6 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 source/xxhash.c diff --git a/awscrt/checksums.py b/awscrt/checksums.py index abade6e61..54f8b0b84 100644 --- a/awscrt/checksums.py +++ b/awscrt/checksums.py @@ -111,3 +111,63 @@ def combine_crc64nvme(crc64nvme_result1: int, crc64nvme_result2: int, data_lengt The combined CRC64-NVME checksum as if computed over the concatenated data """ return _awscrt.checksums_crc64nvme_combine(crc64nvme_result1, crc64nvme_result2, data_length2) + +class XXHash(NativeResource): + def __init__(self, binding): + super().__init__() + self._binding = binding + + @staticmethod + def new_xxhash64(seed: int = 0) -> 'XXHash': + """ + Generates a new instance of XXHash64 hash. + """ + return XXHash(binding=_awscrt.xxhash64_new(seed)) + + @staticmethod + def new_xxhash3_64(seed: int = 0) -> 'XXHash': + """ + Generates a new instance of XXHash3_64 hash. + """ + return XXHash(binding=_awscrt.xxhash3_64_new(seed)) + + @staticmethod + def new_xxhash3_128(seed: int = 0) -> 'XXHash': + """ + Generates a new instance of XXHash3_128 hash. + """ + return XXHash(binding=_awscrt.xxhash3_128_new(seed)) + + @staticmethod + def compute_xxhash64(input: Union[bytes, bytearray, memoryview], seed: int = 0) -> bytes: + """ + One-shot compute of xxhash64 + """ + return _awscrt.xxhash64_compute(input, seed) + + @staticmethod + def compute_xxhash3_64(input: Union[bytes, bytearray, memoryview], seed: int = 0) -> bytes: + """ + One-shot compute of xxhash3_64 + """ + return _awscrt.xxhash3_64_compute(input, seed) + + @staticmethod + def compute_xxhash3_128(input: Union[bytes, bytearray, memoryview], seed: int = 0) -> bytes: + """ + One-shot compute of xxhash3_128 + """ + return _awscrt.xxhash3_128_compute(input, seed) + + def update(self, input: Union[bytes, bytearray, memoryview]): + """ + Updates hash with the provided input. + """ + _awscrt.xxhash_update(self._binding, input) + + def finalize(self) -> bytes: + """ + Finalizes hash. + """ + return _awscrt.xxhash_finalize(self._binding, input) + diff --git a/crt/aws-checksums b/crt/aws-checksums index 270b15acc..c412c6360 160000 --- a/crt/aws-checksums +++ b/crt/aws-checksums @@ -1 +1 @@ -Subproject commit 270b15acc1b2125340ec1c6dda6cc3c28ef0fa44 +Subproject commit c412c636091501c2cd544d23664c8d14999e9dcc diff --git a/source/checksums.h b/source/checksums.h index cb6464f3e..fd207d6c8 100644 --- a/source/checksums.h +++ b/source/checksums.h @@ -13,4 +13,13 @@ PyObject *aws_py_checksums_crc32_combine(PyObject *self, PyObject *args); PyObject *aws_py_checksums_crc32c_combine(PyObject *self, PyObject *args); PyObject *aws_py_checksums_crc64nvme_combine(PyObject *self, PyObject *args); +PyObject *aws_py_xxhash64_new(PyObject *self, PyObject *args); +PyObject *aws_py_xxhash3_64_new(PyObject *self, PyObject *args); +PyObject *aws_py_xxhash3_128_new(PyObject *self, PyObject *args); +PyObject *aws_py_xxhash64_compute(PyObject *self, PyObject *args); +PyObject *aws_py_xxhash3_64_compute(PyObject *self, PyObject *args); +PyObject *aws_py_xxhash3_128_compute(PyObject *self, PyObject *args); +PyObject *aws_py_xxhash_update(PyObject *self, PyObject *args); +PyObject *aws_py_xxhash3_finalize(PyObject *self, PyObject *args); + #endif /* AWS_CRT_PYTHON_CHECKSUMS_H */ diff --git a/source/module.c b/source/module.c index dd346747e..0b752e03d 100644 --- a/source/module.c +++ b/source/module.c @@ -863,6 +863,16 @@ static PyMethodDef s_module_methods[] = { AWS_PY_METHOD_DEF(checksums_crc32c_combine, METH_VARARGS), AWS_PY_METHOD_DEF(checksums_crc64nvme_combine, METH_VARARGS), + /* XXHash Checksum primitives */ + AWS_PY_METHOD_DEF(xxhash64_new, METH_VARARGS), + AWS_PY_METHOD_DEF(xxhash3_64_new, METH_VARARGS), + AWS_PY_METHOD_DEF(xxhash3_128_new, METH_VARARGS), + AWS_PY_METHOD_DEF(xxhash64_compute, METH_VARARGS), + AWS_PY_METHOD_DEF(xxhash3_64_compute, METH_VARARGS), + AWS_PY_METHOD_DEF(xxhash3_128_compute, METH_VARARGS), + AWS_PY_METHOD_DEF(xxhash_update, METH_VARARGS), + AWS_PY_METHOD_DEF(xxhash_finalize, METH_VARARGS), + /* HTTP */ AWS_PY_METHOD_DEF(http_connection_close, METH_VARARGS), AWS_PY_METHOD_DEF(http_connection_is_open, METH_VARARGS), diff --git a/source/xxhash.c b/source/xxhash.c new file mode 100644 index 000000000..fd39bb3d6 --- /dev/null +++ b/source/xxhash.c @@ -0,0 +1,230 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include "checksums.h" + +#include "aws/checksums/xxhash.h" + +const char *s_capsule_name_xxhash = "aws_xxhash"; + +static void s_xxhash_destructor(PyObject *xxhash_capsule) { + struct xxhash *hash = PyCapsule_GetPointer(xxhash_capsule, s_capsule_name_xxhash); + assert(hash); + + aws_xxhash_destroy(hash); +} + +PyObject *aws_py_xxhash64_new(PyObject *self, PyObject *args) { + PyObject *py_seed; + + if (!PyArg_ParseTuple(args, "O", &py_seed)) { + return NULL; + } + + uint64_t seed = PyLong_AsUnsignedLongLong(py_seed); + + if (seed == (uint64_t)-1 && PyErr_Occurred()) { + return NULL; + } + + PyObject *capsule = NULL; + struct aws_allocator *allocator = aws_py_get_allocator(); + + struct xxhash *hash = aws_xxhash3_128_new(allocator, seed); + + if (hash == NULL) { + return PyErr_AwsLastError(); + } + + capsule = PyCapsule_New(hash, s_capsule_name_xxhash, s_xxhash_destructor); + + if (capsule == NULL) { + aws_xxhash_destroy(hash); + } + + return capsule; +} + +PyObject *aws_py_xxhash3_64_new(PyObject *self, PyObject *args) { + PyObject *py_seed; + + if (!PyArg_ParseTuple(args, "O", &py_seed)) { + return NULL; + } + + uint64_t seed = PyLong_AsUnsignedLongLong(py_seed); + + if (seed == (uint64_t)-1 && PyErr_Occurred()) { + return NULL; + } + + PyObject *capsule = NULL; + struct aws_allocator *allocator = aws_py_get_allocator(); + + struct xxhash *hash = aws_xxhash3_128_new(allocator, seed); + + if (hash == NULL) { + return PyErr_AwsLastError(); + } + + capsule = PyCapsule_New(hash, s_capsule_name_xxhash, s_xxhash_destructor); + + if (capsule == NULL) { + aws_xxhash_destroy(hash); + } + + return capsule; +} + +PyObject *aws_py_xxhash3_128_new(PyObject *self, PyObject *args) { + PyObject *py_seed; + + if (!PyArg_ParseTuple(args, "O", &py_seed)) { + return NULL; + } + + uint64_t seed = PyLong_AsUnsignedLongLong(py_seed); + + if (seed == (uint64_t)-1 && PyErr_Occurred()) { + return NULL; + } + + PyObject *capsule = NULL; + struct aws_allocator *allocator = aws_py_get_allocator(); + + struct xxhash *hash = aws_xxhash3_128_new(allocator, seed); + + if (hash == NULL) { + return PyErr_AwsLastError(); + } + + capsule = PyCapsule_New(hash, s_capsule_name_xxhash, s_xxhash_destructor); + + if (capsule == NULL) { + aws_xxhash_destroy(hash); + } + + return capsule; +} + +PyObject *aws_py_xxhash64_compute(PyObject *self, PyObject *args) { + struct aws_byte_cursor input; + PyObject *py_seed; + if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, py_seed)) { + return NULL; + } + + uint64_t seed = PyLong_AsUnsignedLongLong(py_seed); + + if (seed == (uint64_t)-1 && PyErr_Occurred()) { + return NULL; + } + + struct aws_allocator *allocator = aws_py_get_allocator(); + struct aws_byte_buf buf; + aws_byte_buf_init(&buf, allocator, 8); + + if (aws_xxhash64_compute(seed, input, &buf)) { + return PyErr_AwsLastError(); + } + + PyObject *ret = PyBytes_FromStringAndSize((const char *)buf.buffer, buf.len); + aws_byte_buf_clean_up_secure(&buf); + return ret; +} + +PyObject *aws_py_xxhash3_64_compute(PyObject *self, PyObject *args) { + struct aws_byte_cursor input; + PyObject *py_seed; + if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, py_seed)) { + return NULL; + } + + uint64_t seed = PyLong_AsUnsignedLongLong(py_seed); + + if (seed == (uint64_t)-1 && PyErr_Occurred()) { + return NULL; + } + + struct aws_allocator *allocator = aws_py_get_allocator(); + struct aws_byte_buf buf; + aws_byte_buf_init(&buf, allocator, 8); + + if (aws_xxhash3_64_compute(seed, input, &buf)) { + return PyErr_AwsLastError(); + } + + PyObject *ret = PyBytes_FromStringAndSize((const char *)buf.buffer, buf.len); + aws_byte_buf_clean_up_secure(&buf); + return ret; +} + +PyObject *aws_py_xxhash3_128_compute(PyObject *self, PyObject *args) { + struct aws_byte_cursor input; + PyObject *py_seed; + if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, py_seed)) { + return NULL; + } + + uint64_t seed = PyLong_AsUnsignedLongLong(py_seed); + + if (seed == (uint64_t)-1 && PyErr_Occurred()) { + return NULL; + } + + struct aws_allocator *allocator = aws_py_get_allocator(); + struct aws_byte_buf buf; + aws_byte_buf_init(&buf, allocator, 8); + + if (aws_xxhash3_128_compute(seed, input, &buf)) { + return PyErr_AwsLastError(); + } + + PyObject *ret = PyBytes_FromStringAndSize((const char *)buf.buffer, buf.len); + aws_byte_buf_clean_up_secure(&buf); + return ret; +} + +PyObject *aws_py_xxhash_update(PyObject *self, PyObject *args) { + struct aws_byte_cursor input; + PyObject *xxhash_capsule = NULL; + if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, xxhash_capsule)) { + return NULL; + } + + struct aws_xxhash *hash = PyCapsule_GetPointer(xxhash_capsule, s_capsule_name_xxhash); + if (hash == NULL) { + return NULL; + } + + if (aws_xxhash_update(hash, input)) { + PyErr_AwsLastError(); + } +} + +PyObject *aws_py_xxhash3_finalize(PyObject *self, PyObject *args) { + PyObject *xxhash_capsule = NULL; + if (!PyArg_ParseTuple(args, "0", xxhash_capsule)) { + return NULL; + } + + struct aws_xxhash *hash = PyCapsule_GetPointer(xxhash_capsule, s_capsule_name_xxhash); + if (hash == NULL) { + return NULL; + } + + struct aws_allocator *allocator = aws_py_get_allocator(); + struct aws_byte_buf buf; + aws_byte_buf_init(&buf, allocator, 16); + + if (aws_xxhash_finalize(hash, &buf)) { + aws_byte_buf_clean_up_secure(buf); + return PyErr_AwsLastError(); + } + + PyObject *ret = PyBytes_FromStringAndSize((const char *)buf.buffer, buf.len); + aws_byte_buf_clean_up_secure(&buf); + return ret; +} diff --git a/test/test_checksums.py b/test/test_checksums.py index 91890ceb4..3a5ceef08 100644 --- a/test/test_checksums.py +++ b/test/test_checksums.py @@ -4,6 +4,7 @@ from test import NativeResourceTest from awscrt import checksums +from awscrt.checksums import XXHash import unittest import sys @@ -218,6 +219,51 @@ def test_combine_invalid_inputs(self): # Result should be an integer self.assertIsInstance(result, int) + def test_xxhash64_piping(self): + """Test xxhash64 piping from native side""" + data = b"Hello world" + + out = XXHash.compute_xxhash64(data) + + expected = bytes([0xc5, 0x00, 0xb0, 0xc9, 0x12, 0xb3, 0x76, 0xd8]) + + self.assertEqual(out, expected) + + hash = XXHash.new_xxhash64() + hash.update(data) + out2 = hash.finalize() + self.assertEqual(out2, expected) + + def test_xxhash3_64_piping(self): + """Test xxhash3_64 piping from native side""" + data = b"Hello world" + + out = XXHash.compute_xxhash3_64(data) + + expected = bytes([0xb6, 0xac, 0xb9, 0xd8, 0x4a, 0x38, 0xff, 0x74]) + + self.assertEqual(out, expected) + + hash = XXHash.new_xxhash3_64() + hash.update(data) + out2 = hash.finalize() + self.assertEqual(out2, expected) + + def test_xxhash3_128_piping(self): + """Test xxhash3_128 piping from native side""" + data = b"Hello world" + + out = XXHash.compute_xxhash3_128(data) + + expected = bytes([0x73, 0x51, 0xf8, 0x98, 0x12, 0xf9, 0x73, 0x82, + 0xb9, 0x1d, 0x05, 0xb3, 0x1e, 0x04, 0xdd, 0x7f]) + + self.assertEqual(out, expected) + + hash = XXHash.new_xxhash3_128() + hash.update(data) + out2 = hash.finalize() + self.assertEqual(out2, expected) if __name__ == '__main__': unittest.main() From f675378cc93f30e639292f8e1f6024671c4f4db6 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 01:47:16 -0800 Subject: [PATCH 02/22] fix module --- source/xxhash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/xxhash.c b/source/xxhash.c index fd39bb3d6..21970207f 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -204,7 +204,7 @@ PyObject *aws_py_xxhash_update(PyObject *self, PyObject *args) { } } -PyObject *aws_py_xxhash3_finalize(PyObject *self, PyObject *args) { +PyObject *aws_py_xxhash_finalize(PyObject *self, PyObject *args) { PyObject *xxhash_capsule = NULL; if (!PyArg_ParseTuple(args, "0", xxhash_capsule)) { return NULL; From 42b0c22f11a1ad80ebe1ffa53a5785a163a1c529 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 01:50:56 -0800 Subject: [PATCH 03/22] lint --- awscrt/checksums.py | 16 ++++++++-------- source/checksums.h | 2 +- test/test_checksums.py | 5 +++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/awscrt/checksums.py b/awscrt/checksums.py index 54f8b0b84..e68cda281 100644 --- a/awscrt/checksums.py +++ b/awscrt/checksums.py @@ -112,6 +112,7 @@ def combine_crc64nvme(crc64nvme_result1: int, crc64nvme_result2: int, data_lengt """ return _awscrt.checksums_crc64nvme_combine(crc64nvme_result1, crc64nvme_result2, data_length2) + class XXHash(NativeResource): def __init__(self, binding): super().__init__() @@ -123,51 +124,50 @@ def new_xxhash64(seed: int = 0) -> 'XXHash': Generates a new instance of XXHash64 hash. """ return XXHash(binding=_awscrt.xxhash64_new(seed)) - + @staticmethod def new_xxhash3_64(seed: int = 0) -> 'XXHash': """ Generates a new instance of XXHash3_64 hash. """ return XXHash(binding=_awscrt.xxhash3_64_new(seed)) - + @staticmethod def new_xxhash3_128(seed: int = 0) -> 'XXHash': """ Generates a new instance of XXHash3_128 hash. """ return XXHash(binding=_awscrt.xxhash3_128_new(seed)) - + @staticmethod def compute_xxhash64(input: Union[bytes, bytearray, memoryview], seed: int = 0) -> bytes: """ One-shot compute of xxhash64 """ return _awscrt.xxhash64_compute(input, seed) - + @staticmethod def compute_xxhash3_64(input: Union[bytes, bytearray, memoryview], seed: int = 0) -> bytes: """ One-shot compute of xxhash3_64 """ return _awscrt.xxhash3_64_compute(input, seed) - + @staticmethod def compute_xxhash3_128(input: Union[bytes, bytearray, memoryview], seed: int = 0) -> bytes: """ One-shot compute of xxhash3_128 """ return _awscrt.xxhash3_128_compute(input, seed) - + def update(self, input: Union[bytes, bytearray, memoryview]): """ Updates hash with the provided input. """ _awscrt.xxhash_update(self._binding, input) - + def finalize(self) -> bytes: """ Finalizes hash. """ return _awscrt.xxhash_finalize(self._binding, input) - diff --git a/source/checksums.h b/source/checksums.h index fd207d6c8..7bd5b7441 100644 --- a/source/checksums.h +++ b/source/checksums.h @@ -20,6 +20,6 @@ PyObject *aws_py_xxhash64_compute(PyObject *self, PyObject *args); PyObject *aws_py_xxhash3_64_compute(PyObject *self, PyObject *args); PyObject *aws_py_xxhash3_128_compute(PyObject *self, PyObject *args); PyObject *aws_py_xxhash_update(PyObject *self, PyObject *args); -PyObject *aws_py_xxhash3_finalize(PyObject *self, PyObject *args); +PyObject *aws_py_xxhash_finalize(PyObject *self, PyObject *args); #endif /* AWS_CRT_PYTHON_CHECKSUMS_H */ diff --git a/test/test_checksums.py b/test/test_checksums.py index 3a5ceef08..1e88300e2 100644 --- a/test/test_checksums.py +++ b/test/test_checksums.py @@ -255,8 +255,8 @@ def test_xxhash3_128_piping(self): out = XXHash.compute_xxhash3_128(data) - expected = bytes([0x73, 0x51, 0xf8, 0x98, 0x12, 0xf9, 0x73, 0x82, - 0xb9, 0x1d, 0x05, 0xb3, 0x1e, 0x04, 0xdd, 0x7f]) + expected = bytes([0x73, 0x51, 0xf8, 0x98, 0x12, 0xf9, 0x73, 0x82, + 0xb9, 0x1d, 0x05, 0xb3, 0x1e, 0x04, 0xdd, 0x7f]) self.assertEqual(out, expected) @@ -265,5 +265,6 @@ def test_xxhash3_128_piping(self): out2 = hash.finalize() self.assertEqual(out2, expected) + if __name__ == '__main__': unittest.main() From 4a62f1be7b106acf7027ea4a04c4ef70a1d67754 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 01:54:38 -0800 Subject: [PATCH 04/22] cast --- source/xxhash.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/xxhash.c b/source/xxhash.c index 21970207f..66af80753 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -10,7 +10,7 @@ const char *s_capsule_name_xxhash = "aws_xxhash"; static void s_xxhash_destructor(PyObject *xxhash_capsule) { - struct xxhash *hash = PyCapsule_GetPointer(xxhash_capsule, s_capsule_name_xxhash); + struct aws_xxhash *hash = PyCapsule_GetPointer(xxhash_capsule, s_capsule_name_xxhash); assert(hash); aws_xxhash_destroy(hash); @@ -32,7 +32,7 @@ PyObject *aws_py_xxhash64_new(PyObject *self, PyObject *args) { PyObject *capsule = NULL; struct aws_allocator *allocator = aws_py_get_allocator(); - struct xxhash *hash = aws_xxhash3_128_new(allocator, seed); + struct aws_xxhash *hash = aws_xxhash3_128_new(allocator, seed); if (hash == NULL) { return PyErr_AwsLastError(); @@ -63,7 +63,7 @@ PyObject *aws_py_xxhash3_64_new(PyObject *self, PyObject *args) { PyObject *capsule = NULL; struct aws_allocator *allocator = aws_py_get_allocator(); - struct xxhash *hash = aws_xxhash3_128_new(allocator, seed); + struct aws_xxhash *hash = aws_xxhash3_128_new(allocator, seed); if (hash == NULL) { return PyErr_AwsLastError(); @@ -94,7 +94,7 @@ PyObject *aws_py_xxhash3_128_new(PyObject *self, PyObject *args) { PyObject *capsule = NULL; struct aws_allocator *allocator = aws_py_get_allocator(); - struct xxhash *hash = aws_xxhash3_128_new(allocator, seed); + struct aws_xxhash *hash = aws_xxhash3_128_new(allocator, seed); if (hash == NULL) { return PyErr_AwsLastError(); From b628f1c8fd49255a165e528dc17cd64b1de60f55 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 01:56:57 -0800 Subject: [PATCH 05/22] build --- source/xxhash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/xxhash.c b/source/xxhash.c index 66af80753..bda015bc2 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -220,7 +220,7 @@ PyObject *aws_py_xxhash_finalize(PyObject *self, PyObject *args) { aws_byte_buf_init(&buf, allocator, 16); if (aws_xxhash_finalize(hash, &buf)) { - aws_byte_buf_clean_up_secure(buf); + aws_byte_buf_clean_up_secure(&buf); return PyErr_AwsLastError(); } From 40efdd8e89a67e4b4b674603ae5199a4ba12c834 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 02:01:22 -0800 Subject: [PATCH 06/22] test fix --- test/test_checksums.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/test/test_checksums.py b/test/test_checksums.py index 1e88300e2..51f4b3743 100644 --- a/test/test_checksums.py +++ b/test/test_checksums.py @@ -4,11 +4,9 @@ from test import NativeResourceTest from awscrt import checksums -from awscrt.checksums import XXHash import unittest import sys - class TestChecksums(NativeResourceTest): def test_crc32_zeros_one_shot(self): @@ -223,13 +221,13 @@ def test_xxhash64_piping(self): """Test xxhash64 piping from native side""" data = b"Hello world" - out = XXHash.compute_xxhash64(data) + out = checksums.XXHash.compute_xxhash64(data) expected = bytes([0xc5, 0x00, 0xb0, 0xc9, 0x12, 0xb3, 0x76, 0xd8]) self.assertEqual(out, expected) - hash = XXHash.new_xxhash64() + hash = checksums.XXHash.new_xxhash64() hash.update(data) out2 = hash.finalize() self.assertEqual(out2, expected) @@ -238,13 +236,13 @@ def test_xxhash3_64_piping(self): """Test xxhash3_64 piping from native side""" data = b"Hello world" - out = XXHash.compute_xxhash3_64(data) + out = checksums.XXHash.compute_xxhash3_64(data) expected = bytes([0xb6, 0xac, 0xb9, 0xd8, 0x4a, 0x38, 0xff, 0x74]) self.assertEqual(out, expected) - hash = XXHash.new_xxhash3_64() + hash = checksums.XXHash.new_xxhash3_64() hash.update(data) out2 = hash.finalize() self.assertEqual(out2, expected) @@ -253,14 +251,14 @@ def test_xxhash3_128_piping(self): """Test xxhash3_128 piping from native side""" data = b"Hello world" - out = XXHash.compute_xxhash3_128(data) + out = checksums.XXHash.compute_xxhash3_128(data) expected = bytes([0x73, 0x51, 0xf8, 0x98, 0x12, 0xf9, 0x73, 0x82, 0xb9, 0x1d, 0x05, 0xb3, 0x1e, 0x04, 0xdd, 0x7f]) self.assertEqual(out, expected) - hash = XXHash.new_xxhash3_128() + hash = checksums.XXHash.new_xxhash3_128() hash.update(data) out2 = hash.finalize() self.assertEqual(out2, expected) From f059d6f4166c90de5b3da7d896a8ad31b00576da Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 02:02:43 -0800 Subject: [PATCH 07/22] lint --- test/test_checksums.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_checksums.py b/test/test_checksums.py index 51f4b3743..fbe53c31c 100644 --- a/test/test_checksums.py +++ b/test/test_checksums.py @@ -7,6 +7,7 @@ import unittest import sys + class TestChecksums(NativeResourceTest): def test_crc32_zeros_one_shot(self): From 83c54ca89b038dfcb8c0ae061907fccfd4598905 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 02:06:29 -0800 Subject: [PATCH 08/22] missing headers --- awscrt/checksums.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/awscrt/checksums.py b/awscrt/checksums.py index e68cda281..82b06f356 100644 --- a/awscrt/checksums.py +++ b/awscrt/checksums.py @@ -2,6 +2,8 @@ # SPDX-License-Identifier: Apache-2.0. import _awscrt +from awscrt import NativeResource +from typing import Union def crc32(input: bytes, previous_crc32: int = 0) -> int: From 08009f0043a3f2d07a8a98098f15f3fbc55b7ac1 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 12:02:36 -0800 Subject: [PATCH 09/22] buffer --- source/xxhash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/xxhash.c b/source/xxhash.c index bda015bc2..6bf6aa733 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -176,7 +176,7 @@ PyObject *aws_py_xxhash3_128_compute(PyObject *self, PyObject *args) { struct aws_allocator *allocator = aws_py_get_allocator(); struct aws_byte_buf buf; - aws_byte_buf_init(&buf, allocator, 8); + aws_byte_buf_init(&buf, allocator, 16); if (aws_xxhash3_128_compute(seed, input, &buf)) { return PyErr_AwsLastError(); From e9d0b739ebf3a1ad542d800fded30c360262d7e3 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 12:12:08 -0800 Subject: [PATCH 10/22] warnings --- source/xxhash.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/xxhash.c b/source/xxhash.c index 6bf6aa733..17975609a 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -17,6 +17,7 @@ static void s_xxhash_destructor(PyObject *xxhash_capsule) { } PyObject *aws_py_xxhash64_new(PyObject *self, PyObject *args) { + (void)self; PyObject *py_seed; if (!PyArg_ParseTuple(args, "O", &py_seed)) { @@ -48,6 +49,7 @@ PyObject *aws_py_xxhash64_new(PyObject *self, PyObject *args) { } PyObject *aws_py_xxhash3_64_new(PyObject *self, PyObject *args) { + (void)self; PyObject *py_seed; if (!PyArg_ParseTuple(args, "O", &py_seed)) { @@ -79,6 +81,7 @@ PyObject *aws_py_xxhash3_64_new(PyObject *self, PyObject *args) { } PyObject *aws_py_xxhash3_128_new(PyObject *self, PyObject *args) { + (void)self; PyObject *py_seed; if (!PyArg_ParseTuple(args, "O", &py_seed)) { @@ -110,6 +113,7 @@ PyObject *aws_py_xxhash3_128_new(PyObject *self, PyObject *args) { } PyObject *aws_py_xxhash64_compute(PyObject *self, PyObject *args) { + (void)self; struct aws_byte_cursor input; PyObject *py_seed; if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, py_seed)) { @@ -136,6 +140,7 @@ PyObject *aws_py_xxhash64_compute(PyObject *self, PyObject *args) { } PyObject *aws_py_xxhash3_64_compute(PyObject *self, PyObject *args) { + (void)self; struct aws_byte_cursor input; PyObject *py_seed; if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, py_seed)) { @@ -162,6 +167,7 @@ PyObject *aws_py_xxhash3_64_compute(PyObject *self, PyObject *args) { } PyObject *aws_py_xxhash3_128_compute(PyObject *self, PyObject *args) { + (void)self; struct aws_byte_cursor input; PyObject *py_seed; if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, py_seed)) { @@ -188,6 +194,7 @@ PyObject *aws_py_xxhash3_128_compute(PyObject *self, PyObject *args) { } PyObject *aws_py_xxhash_update(PyObject *self, PyObject *args) { + (void)self; struct aws_byte_cursor input; PyObject *xxhash_capsule = NULL; if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, xxhash_capsule)) { @@ -205,6 +212,7 @@ PyObject *aws_py_xxhash_update(PyObject *self, PyObject *args) { } PyObject *aws_py_xxhash_finalize(PyObject *self, PyObject *args) { + (void)self; PyObject *xxhash_capsule = NULL; if (!PyArg_ParseTuple(args, "0", xxhash_capsule)) { return NULL; From fd1dd2152e2d6232611908bdcc10edd0ec8e4b4d Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 12:18:14 -0800 Subject: [PATCH 11/22] fix --- source/xxhash.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/xxhash.c b/source/xxhash.c index 17975609a..768b8671a 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -116,7 +116,7 @@ PyObject *aws_py_xxhash64_compute(PyObject *self, PyObject *args) { (void)self; struct aws_byte_cursor input; PyObject *py_seed; - if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, py_seed)) { + if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, &py_seed)) { return NULL; } @@ -143,7 +143,7 @@ PyObject *aws_py_xxhash3_64_compute(PyObject *self, PyObject *args) { (void)self; struct aws_byte_cursor input; PyObject *py_seed; - if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, py_seed)) { + if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, &py_seed)) { return NULL; } @@ -170,7 +170,7 @@ PyObject *aws_py_xxhash3_128_compute(PyObject *self, PyObject *args) { (void)self; struct aws_byte_cursor input; PyObject *py_seed; - if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, py_seed)) { + if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, &py_seed)) { return NULL; } @@ -197,7 +197,7 @@ PyObject *aws_py_xxhash_update(PyObject *self, PyObject *args) { (void)self; struct aws_byte_cursor input; PyObject *xxhash_capsule = NULL; - if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, xxhash_capsule)) { + if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, &xxhash_capsule)) { return NULL; } @@ -214,7 +214,7 @@ PyObject *aws_py_xxhash_update(PyObject *self, PyObject *args) { PyObject *aws_py_xxhash_finalize(PyObject *self, PyObject *args) { (void)self; PyObject *xxhash_capsule = NULL; - if (!PyArg_ParseTuple(args, "0", xxhash_capsule)) { + if (!PyArg_ParseTuple(args, "0", &xxhash_capsule)) { return NULL; } From 91b52708c179b2369bb52025e146ce8dba1472f6 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 12:25:47 -0800 Subject: [PATCH 12/22] another warning --- source/xxhash.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/xxhash.c b/source/xxhash.c index 768b8671a..b32d0556c 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -193,7 +193,7 @@ PyObject *aws_py_xxhash3_128_compute(PyObject *self, PyObject *args) { return ret; } -PyObject *aws_py_xxhash_update(PyObject *self, PyObject *args) { +PyObject * aws_py_xxhash_update(PyObject *self, PyObject *args) { (void)self; struct aws_byte_cursor input; PyObject *xxhash_capsule = NULL; @@ -209,6 +209,8 @@ PyObject *aws_py_xxhash_update(PyObject *self, PyObject *args) { if (aws_xxhash_update(hash, input)) { PyErr_AwsLastError(); } + + return NULL; } PyObject *aws_py_xxhash_finalize(PyObject *self, PyObject *args) { From 6bda5305e039b5eff220ebad77af512b5b1c3ad3 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 12:40:41 -0800 Subject: [PATCH 13/22] fix format --- source/xxhash.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/xxhash.c b/source/xxhash.c index b32d0556c..5fef9977c 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -116,7 +116,7 @@ PyObject *aws_py_xxhash64_compute(PyObject *self, PyObject *args) { (void)self; struct aws_byte_cursor input; PyObject *py_seed; - if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, &py_seed)) { + if (!PyArg_ParseTuple(args, "y#O", &input.ptr, &input.len, &py_seed)) { return NULL; } @@ -143,7 +143,7 @@ PyObject *aws_py_xxhash3_64_compute(PyObject *self, PyObject *args) { (void)self; struct aws_byte_cursor input; PyObject *py_seed; - if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, &py_seed)) { + if (!PyArg_ParseTuple(args, "y#O", &input.ptr, &input.len, &py_seed)) { return NULL; } @@ -170,7 +170,7 @@ PyObject *aws_py_xxhash3_128_compute(PyObject *self, PyObject *args) { (void)self; struct aws_byte_cursor input; PyObject *py_seed; - if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, &py_seed)) { + if (!PyArg_ParseTuple(args, "y#O", &input.ptr, &input.len, &py_seed)) { return NULL; } @@ -197,7 +197,7 @@ PyObject * aws_py_xxhash_update(PyObject *self, PyObject *args) { (void)self; struct aws_byte_cursor input; PyObject *xxhash_capsule = NULL; - if (!PyArg_ParseTuple(args, "y#0", &input.ptr, &input.len, &xxhash_capsule)) { + if (!PyArg_ParseTuple(args, "y#O", &input.ptr, &input.len, &xxhash_capsule)) { return NULL; } @@ -216,7 +216,7 @@ PyObject * aws_py_xxhash_update(PyObject *self, PyObject *args) { PyObject *aws_py_xxhash_finalize(PyObject *self, PyObject *args) { (void)self; PyObject *xxhash_capsule = NULL; - if (!PyArg_ParseTuple(args, "0", &xxhash_capsule)) { + if (!PyArg_ParseTuple(args, "O", &xxhash_capsule)) { return NULL; } From cdd68d2434d8b48549594dfbbbf90ff2f62b8738 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 12:47:36 -0800 Subject: [PATCH 14/22] order --- source/xxhash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/xxhash.c b/source/xxhash.c index 5fef9977c..118029546 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -197,7 +197,7 @@ PyObject * aws_py_xxhash_update(PyObject *self, PyObject *args) { (void)self; struct aws_byte_cursor input; PyObject *xxhash_capsule = NULL; - if (!PyArg_ParseTuple(args, "y#O", &input.ptr, &input.len, &xxhash_capsule)) { + if (!PyArg_ParseTuple(args, "Oy#", &input.ptr, &input.len, &xxhash_capsule)) { return NULL; } From e28b0a5e3e2b1c7f41493b3031b281d7b7558306 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 12:51:44 -0800 Subject: [PATCH 15/22] order --- source/xxhash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/xxhash.c b/source/xxhash.c index 118029546..3ba4d277f 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -197,7 +197,7 @@ PyObject * aws_py_xxhash_update(PyObject *self, PyObject *args) { (void)self; struct aws_byte_cursor input; PyObject *xxhash_capsule = NULL; - if (!PyArg_ParseTuple(args, "Oy#", &input.ptr, &input.len, &xxhash_capsule)) { + if (!PyArg_ParseTuple(args, "Oy#", &xxhash_capsule, &input.ptr, &input.len)) { return NULL; } From 448029118cb12b48188dc1479133f945ebf44dc8 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 13:04:54 -0800 Subject: [PATCH 16/22] return none --- source/xxhash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/xxhash.c b/source/xxhash.c index 3ba4d277f..6d1b661b7 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -210,7 +210,7 @@ PyObject * aws_py_xxhash_update(PyObject *self, PyObject *args) { PyErr_AwsLastError(); } - return NULL; + return Py_RETURN_NONE; } PyObject *aws_py_xxhash_finalize(PyObject *self, PyObject *args) { From 9b95d511b703f60c91919380ef4e36c21bc76c19 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 13:12:02 -0800 Subject: [PATCH 17/22] ugh --- source/xxhash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/xxhash.c b/source/xxhash.c index 6d1b661b7..008c4ea36 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -210,7 +210,7 @@ PyObject * aws_py_xxhash_update(PyObject *self, PyObject *args) { PyErr_AwsLastError(); } - return Py_RETURN_NONE; + Py_RETURN_NONE; } PyObject *aws_py_xxhash_finalize(PyObject *self, PyObject *args) { From d6cd32e2bd5043f82320bef765360a2fa9229021 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 13:17:02 -0800 Subject: [PATCH 18/22] finalize --- awscrt/checksums.py | 2 +- source/xxhash.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/awscrt/checksums.py b/awscrt/checksums.py index 82b06f356..d2145109b 100644 --- a/awscrt/checksums.py +++ b/awscrt/checksums.py @@ -172,4 +172,4 @@ def finalize(self) -> bytes: """ Finalizes hash. """ - return _awscrt.xxhash_finalize(self._binding, input) + return _awscrt.xxhash_finalize(self._binding) diff --git a/source/xxhash.c b/source/xxhash.c index 008c4ea36..b2c2af4e2 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -193,7 +193,7 @@ PyObject *aws_py_xxhash3_128_compute(PyObject *self, PyObject *args) { return ret; } -PyObject * aws_py_xxhash_update(PyObject *self, PyObject *args) { +PyObject *aws_py_xxhash_update(PyObject *self, PyObject *args) { (void)self; struct aws_byte_cursor input; PyObject *xxhash_capsule = NULL; From 5642cef04c5ef3e07454afce64bd1246f02b49cf Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 13:32:09 -0800 Subject: [PATCH 19/22] typo --- source/xxhash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/xxhash.c b/source/xxhash.c index b2c2af4e2..1700f1a78 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -33,7 +33,7 @@ PyObject *aws_py_xxhash64_new(PyObject *self, PyObject *args) { PyObject *capsule = NULL; struct aws_allocator *allocator = aws_py_get_allocator(); - struct aws_xxhash *hash = aws_xxhash3_128_new(allocator, seed); + struct aws_xxhash *hash = aws_xxhash64_new(allocator, seed); if (hash == NULL) { return PyErr_AwsLastError(); @@ -65,7 +65,7 @@ PyObject *aws_py_xxhash3_64_new(PyObject *self, PyObject *args) { PyObject *capsule = NULL; struct aws_allocator *allocator = aws_py_get_allocator(); - struct aws_xxhash *hash = aws_xxhash3_128_new(allocator, seed); + struct aws_xxhash *hash = aws_xxhash3_64_new(allocator, seed); if (hash == NULL) { return PyErr_AwsLastError(); From e2ca23e32192031e75cdd4a636df934814f4eacd Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 13:49:20 -0800 Subject: [PATCH 20/22] Add attribution note --- NOTICE | 27 +++++++++++++++++++++++++++ README.md | 3 +++ 2 files changed, 30 insertions(+) diff --git a/NOTICE b/NOTICE index 64177a4eb..3e1163c07 100644 --- a/NOTICE +++ b/NOTICE @@ -1,3 +1,30 @@ AWS Crt Python Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0. + +** XXHash - https://xxhash.com/ +Copyright (c) 2012-2021 Yann Collet +All rights reserved. + +BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index 43d019a9e..63082cb08 100644 --- a/README.md +++ b/README.md @@ -147,3 +147,6 @@ AWS_EXTRA_LIB_DIR=C:\path\to\libs;D:\another\path python3 -m pip install . ### Windows SDK Version aws-crt-python builds against windows sdk version `10.0.17763.0` . This is the minimal version required for TLS 1.3 support on Windows. If you need a different Windows SDK version, you can set environment variable `AWS_CRT_WINDOWS_SDK_VERSION=` while building from source: + +### Attribution +This library exposes native XXHash implementation (https://github.com/Cyan4973/xxHash). From 2854b73432a686d6970cded45c261a2c965cecf8 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 15:06:59 -0800 Subject: [PATCH 21/22] error hadnling --- source/xxhash.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/xxhash.c b/source/xxhash.c index 1700f1a78..95d8a93a1 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -131,6 +131,7 @@ PyObject *aws_py_xxhash64_compute(PyObject *self, PyObject *args) { aws_byte_buf_init(&buf, allocator, 8); if (aws_xxhash64_compute(seed, input, &buf)) { + aws_byte_buf_clean_up_secure(&buf); return PyErr_AwsLastError(); } @@ -158,6 +159,7 @@ PyObject *aws_py_xxhash3_64_compute(PyObject *self, PyObject *args) { aws_byte_buf_init(&buf, allocator, 8); if (aws_xxhash3_64_compute(seed, input, &buf)) { + aws_byte_buf_clean_up_secure(&buf); return PyErr_AwsLastError(); } @@ -185,6 +187,7 @@ PyObject *aws_py_xxhash3_128_compute(PyObject *self, PyObject *args) { aws_byte_buf_init(&buf, allocator, 16); if (aws_xxhash3_128_compute(seed, input, &buf)) { + aws_byte_buf_clean_up_secure(&buf); return PyErr_AwsLastError(); } From 57067b260d30c24ed5ac578fd3a11de6e0d3b799 Mon Sep 17 00:00:00 2001 From: DmitriyMusatkin Date: Wed, 11 Feb 2026 22:43:14 -0800 Subject: [PATCH 22/22] add return --- source/xxhash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/xxhash.c b/source/xxhash.c index 95d8a93a1..1fd36b22a 100644 --- a/source/xxhash.c +++ b/source/xxhash.c @@ -210,7 +210,7 @@ PyObject *aws_py_xxhash_update(PyObject *self, PyObject *args) { } if (aws_xxhash_update(hash, input)) { - PyErr_AwsLastError(); + return PyErr_AwsLastError(); } Py_RETURN_NONE;