Skip to content

Release 1.1.0 #130

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Oct 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d9f8678
New dev version
rhpvorderman Aug 3, 2022
9d0d217
Remove large buffer_size for self._buffer as it does not add performance
rhpvorderman Aug 5, 2022
60dcef7
Add braces around if clause
rhpvorderman Sep 27, 2022
2d88fce
Reorder struct with cache locality in mind
rhpvorderman Sep 27, 2022
124280e
Do not check buffer is NULL before freeing
rhpvorderman Sep 27, 2022
3cf0474
Make keywords and format static
rhpvorderman Sep 27, 2022
0298783
Put brackets around if statement
rhpvorderman Sep 27, 2022
44014ce
Inline small functions
rhpvorderman Sep 27, 2022
52183b4
Make gzip check smaller and inline it
rhpvorderman Sep 27, 2022
72091fe
Inline zlib_mem_level_to_isal
rhpvorderman Sep 27, 2022
4236421
Make keywords and format static
rhpvorderman Sep 27, 2022
d8e4cee
Reorder structs so buffers are at the bottom
rhpvorderman Sep 27, 2022
7a34a42
Line length and style fixes
rhpvorderman Sep 27, 2022
a46faa4
Address line length in C files
rhpvorderman Sep 27, 2022
6668f8a
Use multiline command syntax where appropriate
rhpvorderman Sep 27, 2022
d00502c
Add changes to changelog
rhpvorderman Sep 27, 2022
fd28d48
Add comment on struct ordering
rhpvorderman Sep 27, 2022
9084c98
Remove trailing whitespace
rhpvorderman Sep 27, 2022
01b1e02
Merge pull request #126 from pycompression/review
rhpvorderman Sep 27, 2022
d40fe19
Also test on python 3.11
rhpvorderman Oct 11, 2022
b2035ad
Use prerelease version for 3.11
rhpvorderman Oct 11, 2022
9bfcd82
Update changelog with Python 3.11 support.
rhpvorderman Oct 11, 2022
8d03288
Merge pull request #128 from pycompression/py3.11
rhpvorderman Oct 11, 2022
2b83b17
Use more idiomatic switch case instead of if else tree
rhpvorderman Oct 11, 2022
190a5ba
Small code style changes
rhpvorderman Oct 12, 2022
29486d9
Remove the refactorings from the changelog as users are not affected
rhpvorderman Oct 12, 2022
796ee1e
Set a stable version number
rhpvorderman Oct 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ jobs:
- "3.8"
- "3.9"
- "3.10"
- "3.11-dev"
- "pypy-3.7"
- "pypy-3.8"
- "pypy-3.9"
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ Changelog
.. This document is user facing. Please word the changes in such a way
.. that users understand how the changes affect the new version.

version 1.1.0
-----------------
+ Added tests and support for Python 3.11.

version 1.0.1
------------------
+ Fixed failing tests and wheel builds for PyPy.
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def build_isa_l(compiler_command: str, compiler_options: str):

setup(
name="isal",
version="1.0.1",
version="1.1.0",
description="Faster zlib and gzip compatible compression and "
"decompression by providing python bindings for the ISA-L "
"library.",
Expand All @@ -188,6 +188,7 @@ def build_isa_l(compiler_command: str, compiler_options: str):
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Programming Language :: C",
Expand Down
2 changes: 1 addition & 1 deletion src/isal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@
"__version__"
]

__version__ = "1.0.1"
__version__ = "1.1.0"
28 changes: 15 additions & 13 deletions src/isal/_isalmodule.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
// Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
// 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022
// Python Software Foundation; All Rights Reserved
/*
Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022
Python Software Foundation; All Rights Reserved

// This file is part of python-isal which is distributed under the
// PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2.
This file is part of python-isal which is distributed under the
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2.

// This file is not originally from the CPython distribution. But it does contain mostly example code
// from the Python docs. Also dual licensing just for this one file seemed silly.
This file is not originally from the CPython distribution. But it does
contain mostly example code from the Python docs. Also dual licensing just
for this one file seemed silly.
*/

#define PY_SSIZE_T_CLEAN
#include <Python.h>
Expand All @@ -24,20 +27,19 @@ static struct PyModuleDef _isal_module = {
PyMODINIT_FUNC
PyInit__isal(void)
{
PyObject *m;

m = PyModule_Create(&_isal_module);
if (m == NULL)
PyObject *m = PyModule_Create(&_isal_module);
if (m == NULL) {
return NULL;

}
PyModule_AddIntMacro(m, ISAL_MAJOR_VERSION);
PyModule_AddIntMacro(m, ISAL_MINOR_VERSION);
PyModule_AddIntMacro(m, ISAL_PATCH_VERSION);

PyObject *isal_version = PyUnicode_FromFormat(
"%d.%d.%d", ISAL_MAJOR_VERSION, ISAL_MINOR_VERSION, ISAL_PATCH_VERSION);
if (isal_version == NULL)
if (isal_version == NULL) {
return NULL;
}
PyModule_AddObject(m, "ISAL_VERSION", isal_version);
return m;
}
2 changes: 1 addition & 1 deletion src/isal/igzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def __init__(self, filename=None, mode=None,
0)
if self.mode == READ:
raw = _IGzipReader(self.fileobj)
self._buffer = io.BufferedReader(raw, buffer_size=READ_BUFFER_SIZE)
self._buffer = io.BufferedReader(raw)

def __repr__(self):
s = repr(self.fileobj)
Expand Down
125 changes: 68 additions & 57 deletions src/isal/igzip_libmodule.c
Original file line number Diff line number Diff line change
@@ -1,45 +1,47 @@
// Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
// 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022
// Python Software Foundation; All Rights Reserved

// This file is part of python-isal which is distributed under the
// PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2.

// This file was modified from Cpython Modules/bz2module.c file from the 3.9
// branch.

// Changes compared to CPython:
// - The BZ2Decompressor has been used as a basis for IgzipDecompressor.
// Functionality is almost the same. IgzipDecompressor does have a more
// elaborate __init__ to set settings. It also implements decompress_buf more
// akin to how decompression is implemented in isal_shared.h
// - Constants were added that are particular to igzip_lib.
// - Argument parsers were written using th CPython API rather than argument
// clinic.
/*
Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022
Python Software Foundation; All Rights Reserved

This file is part of python-isal which is distributed under the
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2.

This file was modified from Cpython Modules/bz2module.c file from the 3.9
branch.

Changes compared to CPython:
- The BZ2Decompressor has been used as a basis for IgzipDecompressor.
Functionality is almost the same. IgzipDecompressor does have a more
elaborate __init__ to set settings. It also implements decompress_buf more
akin to how decompression is implemented in isal_shared.h
- Constants were added that are particular to igzip_lib.
- Argument parsers were written using th CPython API rather than argument
clinic.
*/

#include "isal_shared.h"

typedef struct {
PyObject_HEAD
struct inflate_state state;
char eof; /* T_BOOL expects a char */
PyObject *unused_data;
PyObject *zdict;
char needs_input;
uint8_t *input_buffer;
Py_ssize_t input_buffer_size;

/* inflate_state>avail_in is only 32 bit, so we store the true length
separately. Conversion and looping is encapsulated in
decompress_buf() */
Py_ssize_t avail_in_real;
char eof; /* T_BOOL expects a char */
char needs_input;
/* Struct inflate state contains a massive buffer at the end. Put it at
the end of the IgzipDecompressor so members can be accessed easily. */
struct inflate_state state;
} IgzipDecompressor;

static void
IgzipDecompressor_dealloc(IgzipDecompressor *self)
{
if(self->input_buffer != NULL)
PyMem_Free(self->input_buffer);
PyMem_Free(self->input_buffer);
Py_CLEAR(self->unused_data);
Py_CLEAR(self->zdict);
Py_TYPE(self)->tp_free((PyObject *)self);
Expand All @@ -55,23 +57,23 @@ decompress_buf(IgzipDecompressor *self, Py_ssize_t max_length)
/* data_size is strictly positive, but because we repeatedly have to
compare against max_length and PyBytes_GET_SIZE we declare it as
signed */
PyObject * RetVal = NULL;
PyObject *RetVal = NULL;
Py_ssize_t hard_limit;

Py_ssize_t obuflen;

int err;

// In Python 3.10 sometimes sys.maxsize is passed by default. In those cases
// we do want to use DEF_BUF_SIZE as start buffer.
/* In Python 3.10 sometimes sys.maxsize is passed by default. In those cases
we do want to use DEF_BUF_SIZE as start buffer. */
if ((max_length < 0) || max_length == PY_SSIZE_T_MAX) {
hard_limit = PY_SSIZE_T_MAX;
obuflen = DEF_BUF_SIZE;
} else {
// Assume that decompressor is used in file decompression with a fixed
// block size of max_length. In that case we will reach max_length almost
// always (except at the end of the file). So it makes sense to allocate
// max_length.
/* Assume that decompressor is used in file decompression with a fixed
block size of max_length. In that case we will reach max_length almost
always (except at the end of the file). So it makes sense to allocate
max_length. */
hard_limit = max_length;
obuflen = max_length;
if (obuflen > DEF_MAX_INITIAL_BUF_SIZE){
Expand Down Expand Up @@ -102,8 +104,10 @@ decompress_buf(IgzipDecompressor *self, Py_ssize_t max_length)
isal_inflate_error(err);
goto error;
}
} while (self->state.avail_out == 0 && self->state.block_state != ISAL_BLOCK_FINISH);
} while(self->avail_in_real != 0 && self->state.block_state != ISAL_BLOCK_FINISH);
} while (self->state.avail_out == 0 &&
self->state.block_state != ISAL_BLOCK_FINISH);
} while(self->avail_in_real != 0 &&
self->state.block_state != ISAL_BLOCK_FINISH);

if (self->state.block_state == ISAL_BLOCK_FINISH)
self->eof = 1;
Expand Down Expand Up @@ -183,13 +187,14 @@ decompress(IgzipDecompressor *self, uint8_t *data, size_t len, Py_ssize_t max_le
self->needs_input = 0;
Py_ssize_t bytes_in_bitbuffer = bitbuffer_size(&(self->state));
if (self->avail_in_real + bytes_in_bitbuffer > 0) {
PyObject * new_data = PyBytes_FromStringAndSize(
PyObject *new_data = PyBytes_FromStringAndSize(
NULL, self->avail_in_real + bytes_in_bitbuffer);
if (new_data == NULL)
goto error;
char * new_data_ptr = PyBytes_AS_STRING(new_data);
char *new_data_ptr = PyBytes_AS_STRING(new_data);
bitbuffer_copy(&(self->state), new_data_ptr, bytes_in_bitbuffer);
memcpy(new_data_ptr + bytes_in_bitbuffer, self->state.next_in, self->avail_in_real);
memcpy(new_data_ptr + bytes_in_bitbuffer, self->state.next_in,
self->avail_in_real);
Py_XSETREF(self->unused_data, new_data);
}
}
Expand All @@ -208,7 +213,7 @@ decompress(IgzipDecompressor *self, uint8_t *data, size_t len, Py_ssize_t max_le
/* Discard buffer if it's too small
(resizing it may needlessly copy the current contents) */
if (self->input_buffer != NULL &&
self->input_buffer_size < self->avail_in_real) {
self->input_buffer_size < self->avail_in_real) {
PyMem_Free(self->input_buffer);
self->input_buffer = NULL;
}
Expand Down Expand Up @@ -257,13 +262,14 @@ PyDoc_STRVAR(igzip_lib_compress__doc__,
" the header and trailer are controlled by the flag parameter.");

#define IGZIP_LIB_COMPRESS_METHODDEF \
{"compress", (PyCFunction)(void(*)(void))igzip_lib_compress, METH_VARARGS|METH_KEYWORDS, igzip_lib_compress__doc__}
{"compress", (PyCFunction)(void(*)(void))igzip_lib_compress, \
METH_VARARGS|METH_KEYWORDS, igzip_lib_compress__doc__}

static PyObject *
igzip_lib_compress(PyObject *module, PyObject *args, PyObject *kwargs)
{
char *keywords[] = {"", "level", "flag", "mem_level", "hist_bits", NULL};
char *format ="y*|iiii:compress";
static char *keywords[] = {"", "level", "flag", "mem_level", "hist_bits", NULL};
static char *format ="y*|iiii:compress";
Py_buffer data = {NULL, NULL};
int level = ISAL_DEFAULT_COMPRESSION;
int flag = COMP_DEFLATE;
Expand Down Expand Up @@ -298,13 +304,14 @@ PyDoc_STRVAR(igzip_lib_decompress__doc__,
" The initial output buffer size.");

#define IGZIP_LIB_DECOMPRESS_METHODDEF \
{"decompress", (PyCFunction)(void(*)(void))igzip_lib_decompress, METH_VARARGS|METH_KEYWORDS, igzip_lib_decompress__doc__}
{"decompress", (PyCFunction)(void(*)(void))igzip_lib_decompress, \
METH_VARARGS|METH_KEYWORDS, igzip_lib_decompress__doc__}

static PyObject *
igzip_lib_decompress(PyObject *module, PyObject *args, PyObject *kwargs)
{
char *keywords[] = {"", "flag", "hist_bits", "bufsize", NULL};
char *format ="y*|iin:decompress";
static char *keywords[] = {"", "flag", "hist_bits", "bufsize", NULL};
static char *format ="y*|iin:decompress";
Py_buffer data = {NULL, NULL};
int flag = DECOMP_DEFLATE;
int hist_bits = ISAL_DEF_MAX_HIST_BITS;
Expand All @@ -315,7 +322,7 @@ igzip_lib_decompress(PyObject *module, PyObject *args, PyObject *kwargs)
&data, &flag, &hist_bits, &bufsize)) {
return NULL;
}
PyObject * return_value = igzip_lib_decompress_impl(&data, flag, hist_bits, bufsize);
PyObject *return_value = igzip_lib_decompress_impl(&data, flag, hist_bits, bufsize);
PyBuffer_Release(&data);
return return_value;
}
Expand All @@ -340,13 +347,16 @@ PyDoc_STRVAR(igzip_lib_IgzipDecompressor_decompress__doc__,
"the unused_data attribute.");

#define IGZIP_LIB_IGZIPDECOMPRESSOR_DECOMPRESS_METHODDEF \
{"decompress", (PyCFunction)(void(*)(void))igzip_lib_IgzipDecompressor_decompress, METH_VARARGS|METH_KEYWORDS, igzip_lib_IgzipDecompressor_decompress__doc__}
{"decompress", (PyCFunction)(void(*)(void))igzip_lib_IgzipDecompressor_decompress, \
METH_VARARGS|METH_KEYWORDS, igzip_lib_IgzipDecompressor_decompress__doc__}

static PyObject *
igzip_lib_IgzipDecompressor_decompress(IgzipDecompressor *self, PyObject *args, PyObject *kwargs)
igzip_lib_IgzipDecompressor_decompress(IgzipDecompressor *self,
PyObject *args,
PyObject *kwargs)
{
char *keywords[] = {"", "max_length", NULL};
char *format = "y*|n:decompress";
static char *keywords[] = {"", "max_length", NULL};
static char *format = "y*|n:decompress";
Py_buffer data = {NULL, NULL};
Py_ssize_t max_length = -1;

Expand Down Expand Up @@ -383,8 +393,8 @@ igzip_lib_IgzipDecompressor__new__(PyTypeObject *type,
PyObject *args,
PyObject *kwargs)
{
char *keywords[] = {"flag", "hist_bits", "zdict", NULL};
char *format = "|iiO:IgzipDecompressor";
static char *keywords[] = {"flag", "hist_bits", "zdict", NULL};
static char *format = "|iiO:IgzipDecompressor";
int flag = ISAL_DEFLATE;
int hist_bits = ISAL_DEF_MAX_HIST_BITS;
PyObject *zdict = NULL;
Expand Down Expand Up @@ -458,8 +468,9 @@ static PyMemberDef IgzipDecompressor_members[] = {
READONLY, IgzipDecompressor_unused_data__doc__},
{"needs_input", T_BOOL, offsetof(IgzipDecompressor, needs_input), READONLY,
IgzipDecompressor_needs_input_doc},
{"crc", T_UINT, offsetof(IgzipDecompressor, state) + offsetof(struct inflate_state, crc), READONLY,
IgzipDecompressor_crc_doc},
{"crc", T_UINT,
offsetof(IgzipDecompressor, state) + offsetof(struct inflate_state, crc),
READONLY, IgzipDecompressor_crc_doc},
{NULL}
};

Expand Down Expand Up @@ -561,9 +572,7 @@ static struct PyModuleDef igzip_lib_module = {
PyMODINIT_FUNC
PyInit_igzip_lib(void)
{
PyObject *m;

m = PyModule_Create(&igzip_lib_module);
PyObject *m = PyModule_Create(&igzip_lib_module);
if (m == NULL)
return NULL;

Expand All @@ -580,10 +589,12 @@ PyInit_igzip_lib(void)
return NULL;
}

if (PyType_Ready(&IgzipDecompressor_Type) != 0)
if (PyType_Ready(&IgzipDecompressor_Type) != 0) {
return NULL;
}
Py_INCREF(&IgzipDecompressor_Type);
if (PyModule_AddObject(m, "IgzipDecompressor", (PyObject *)&IgzipDecompressor_Type) < 0) {
if (PyModule_AddObject(m, "IgzipDecompressor",
(PyObject *)&IgzipDecompressor_Type) < 0) {
return NULL;
}

Expand Down
Loading