Skip to content

Commit 082445c

Browse files
eustascopybara-github
authored andcommitted
support multi-phase initialization
PiperOrigin-RevId: 811797785
1 parent d74b0a4 commit 082445c

File tree

1 file changed

+96
-49
lines changed

1 file changed

+96
-49
lines changed

python/_brotli.c

Lines changed: 96 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include <assert.h>
2-
#include <stdio.h>
32
#include <stddef.h>
3+
#include <stdio.h>
44
#include <stdlib.h>
55
#include <string.h>
66
#define PY_SSIZE_T_CLEAN 1
@@ -18,7 +18,12 @@
1818
#define PY_GET_TYPE(Obj) ((Obj)->ob_type)
1919
#endif
2020

21+
static const char kErrorAttr[] = "error";
22+
#if PY_MAJOR_VERSION >= 3
23+
static const char kModuleAttr[] = "_module";
24+
#else
2125
static PyObject* BrotliError;
26+
#endif
2227

2328
static const char kInvalidBufferError[] =
2429
"brotli: data must be a C-contiguous buffer";
@@ -195,8 +200,33 @@ PyDoc_STRVAR(brotli_doc,
195200
"Implementation module for the Brotli library.");
196201
/* clang-format on */
197202

198-
static void set_brotli_exception(const char* msg) {
203+
/*
204+
Sets an exception with the given message.
205+
206+
`context` could be a module, a module type, or an instance of a module type.
207+
*/
208+
static void set_brotli_exception(PyObject* context, const char* msg) {
209+
#if PY_MAJOR_VERSION >= 3
210+
PyObject* error = NULL;
211+
assert(context != NULL);
212+
213+
if (PyModule_Check(context)) {
214+
error = PyObject_GetAttrString(context, kErrorAttr);
215+
} else {
216+
PyObject* type =
217+
PyType_Check(context) ? context : (PyObject*)PY_GET_TYPE(context);
218+
PyObject* module = PyObject_GetAttrString(type, kModuleAttr);
219+
if (!module) return; /* AttributeError raised. */
220+
error = PyObject_GetAttrString(module, kErrorAttr);
221+
Py_DECREF(module);
222+
}
223+
224+
if (error == NULL) return; /* AttributeError raised. */
225+
PyErr_SetString(error, msg);
226+
Py_DECREF(error);
227+
#else
199228
PyErr_SetString(BrotliError, msg);
229+
#endif
200230
}
201231

202232
/*
@@ -316,7 +346,7 @@ static PyObject* Buffer_Finish(Buffer* buffer) {
316346

317347
result = PyBytes_FromStringAndSize(NULL, len);
318348
if (result == NULL) {
319-
PyErr_Clear(); /* OOM exception will be raised by callers. */
349+
PyErr_Clear(); /* OOM exception will be raised by callers. */
320350
return NULL;
321351
}
322352
if (len == 0) return result;
@@ -354,7 +384,7 @@ static PyObject* brotli_Compressor_new(PyTypeObject* type, PyObject* args,
354384
self->processing = 0;
355385
self->enc = BrotliEncoderCreateInstance(0, 0, 0);
356386
if (self->enc == NULL) {
357-
set_brotli_exception(kCompressCreateError);
387+
set_brotli_exception((PyObject*)type, kCompressCreateError);
358388
PY_GET_TYPE(self)->tp_free((PyObject*)self);
359389
return NULL;
360390
}
@@ -386,30 +416,30 @@ static int brotli_Compressor_init(PyBrotli_Compressor* self, PyObject* args,
386416
if ((mode == 0) || (mode == 1) || (mode == 2)) {
387417
BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_MODE, (uint32_t)mode);
388418
} else {
389-
set_brotli_exception(kInvalidModeError);
419+
set_brotli_exception((PyObject*)self, kInvalidModeError);
390420
self->healthy = 0;
391421
return -1;
392422
}
393423
if (quality <= 11) {
394424
BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_QUALITY,
395425
(uint32_t)quality);
396426
} else {
397-
set_brotli_exception(kInvalidQualityError);
427+
set_brotli_exception((PyObject*)self, kInvalidQualityError);
398428
self->healthy = 0;
399429
return -1;
400430
}
401431
if ((10 <= lgwin) && (lgwin <= 24)) {
402432
BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_LGWIN, (uint32_t)lgwin);
403433
} else {
404-
set_brotli_exception(kInvalidLgwinError);
434+
set_brotli_exception((PyObject*)self, kInvalidLgwinError);
405435
self->healthy = 0;
406436
return -1;
407437
}
408438
if ((lgblock == 0) || ((16 <= lgblock) && (lgblock <= 24))) {
409439
BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_LGBLOCK,
410440
(uint32_t)lgblock);
411441
} else {
412-
set_brotli_exception(kInvalidLgblockError);
442+
set_brotli_exception((PyObject*)self, kInvalidLgblockError);
413443
self->healthy = 0;
414444
return -1;
415445
}
@@ -470,8 +500,8 @@ static PyObject* compress_stream(PyBrotli_Compressor* self,
470500
if (ok) {
471501
ret = Buffer_Finish(&buffer);
472502
if (ret == NULL) oom = 1;
473-
} else { /* Not ok */
474-
set_brotli_exception(kCompressError);
503+
} else { /* Not ok */
504+
set_brotli_exception((PyObject*)self, kCompressError);
475505
}
476506

477507
error:
@@ -495,11 +525,11 @@ static PyObject* brotli_Compressor_process(PyBrotli_Compressor* self,
495525
Py_buffer input;
496526

497527
if (self->healthy == 0) {
498-
set_brotli_exception(kCompressUnhealthyError);
528+
set_brotli_exception((PyObject*)self, kCompressUnhealthyError);
499529
return NULL;
500530
}
501531
if (self->processing != 0) {
502-
set_brotli_exception(kCompressConcurrentError);
532+
set_brotli_exception((PyObject*)self, kCompressConcurrentError);
503533
return NULL;
504534
}
505535

@@ -522,11 +552,11 @@ static PyObject* brotli_Compressor_flush(PyBrotli_Compressor* self) {
522552
PyObject* ret = NULL;
523553

524554
if (self->healthy == 0) {
525-
set_brotli_exception(kCompressUnhealthyError);
555+
set_brotli_exception((PyObject*)self, kCompressUnhealthyError);
526556
return NULL;
527557
}
528558
if (self->processing != 0) {
529-
set_brotli_exception(kCompressConcurrentError);
559+
set_brotli_exception((PyObject*)self, kCompressConcurrentError);
530560
return NULL;
531561
}
532562

@@ -540,11 +570,11 @@ static PyObject* brotli_Compressor_finish(PyBrotli_Compressor* self) {
540570
PyObject* ret = NULL;
541571

542572
if (self->healthy == 0) {
543-
set_brotli_exception(kCompressUnhealthyError);
573+
set_brotli_exception((PyObject*)self, kCompressUnhealthyError);
544574
return NULL;
545575
}
546576
if (self->processing != 0) {
547-
set_brotli_exception(kCompressConcurrentError);
577+
set_brotli_exception((PyObject*)self, kCompressConcurrentError);
548578
return NULL;
549579
}
550580

@@ -578,7 +608,7 @@ static PyObject* brotli_Decompressor_new(PyTypeObject* type, PyObject* args,
578608

579609
self->dec = BrotliDecoderCreateInstance(0, 0, 0);
580610
if (self->dec == NULL) {
581-
set_brotli_exception(kDecompressCreateError);
611+
set_brotli_exception((PyObject*)type, kDecompressCreateError);
582612
PY_GET_TYPE(self)->tp_free((PyObject*)self);
583613
return NULL;
584614
}
@@ -633,11 +663,11 @@ static PyObject* brotli_Decompressor_process(PyBrotli_Decompressor* self,
633663
int oom = 0;
634664

635665
if (self->healthy == 0) {
636-
set_brotli_exception(kDecompressUnhealthyError);
666+
set_brotli_exception((PyObject*)self, kDecompressUnhealthyError);
637667
return NULL;
638668
}
639669
if (self->processing != 0) {
640-
set_brotli_exception(kDecompressConcurrentError);
670+
set_brotli_exception((PyObject*)self, kDecompressConcurrentError);
641671
return NULL;
642672
}
643673

@@ -654,7 +684,7 @@ static PyObject* brotli_Decompressor_process(PyBrotli_Decompressor* self,
654684

655685
if (self->unconsumed_data_length > 0) {
656686
if (input.len > 0) {
657-
set_brotli_exception(kDecompressSinkError);
687+
set_brotli_exception((PyObject*)self, kDecompressSinkError);
658688
goto finally;
659689
}
660690
next_in = self->unconsumed_data;
@@ -693,7 +723,7 @@ static PyObject* brotli_Decompressor_process(PyBrotli_Decompressor* self,
693723
if (oom) {
694724
goto finally;
695725
} else if (result == BROTLI_DECODER_RESULT_ERROR) {
696-
set_brotli_exception(kDecompressError);
726+
set_brotli_exception((PyObject*)self, kDecompressError);
697727
goto finally;
698728
}
699729

@@ -712,7 +742,7 @@ static PyObject* brotli_Decompressor_process(PyBrotli_Decompressor* self,
712742

713743
if ((result == BROTLI_DECODER_RESULT_SUCCESS) && (avail_in > 0)) {
714744
/* TODO(eustas): Add API to ignore / fetch unused "tail"? */
715-
set_brotli_exception(kDecompressError);
745+
set_brotli_exception((PyObject*)self, kDecompressError);
716746
goto finally;
717747
}
718748

@@ -742,11 +772,11 @@ static PyObject* brotli_Decompressor_process(PyBrotli_Decompressor* self,
742772

743773
static PyObject* brotli_Decompressor_is_finished(PyBrotli_Decompressor* self) {
744774
if (self->healthy == 0) {
745-
set_brotli_exception(kDecompressUnhealthyError);
775+
set_brotli_exception((PyObject*)self, kDecompressUnhealthyError);
746776
return NULL;
747777
}
748778
if (self->processing != 0) {
749-
set_brotli_exception(kDecompressConcurrentError);
779+
set_brotli_exception((PyObject*)self, kDecompressConcurrentError);
750780
return NULL;
751781
}
752782
if (BrotliDecoderIsFinished(self->dec)) {
@@ -759,11 +789,11 @@ static PyObject* brotli_Decompressor_is_finished(PyBrotli_Decompressor* self) {
759789
static PyObject* brotli_Decompressor_can_accept_more_data(
760790
PyBrotli_Decompressor* self) {
761791
if (self->healthy == 0) {
762-
set_brotli_exception(kDecompressUnhealthyError);
792+
set_brotli_exception((PyObject*)self, kDecompressUnhealthyError);
763793
return NULL;
764794
}
765795
if (self->processing != 0) {
766-
set_brotli_exception(kDecompressConcurrentError);
796+
set_brotli_exception((PyObject*)self, kDecompressConcurrentError);
767797
return NULL;
768798
}
769799
if (self->unconsumed_data_length > 0) {
@@ -832,7 +862,7 @@ static PyObject* brotli_decompress(PyObject* self, PyObject* args,
832862
if (oom) {
833863
goto finally;
834864
} else if (result != BROTLI_DECODER_RESULT_SUCCESS || available_in > 0) {
835-
set_brotli_exception(kDecompressError);
865+
set_brotli_exception((PyObject*)self, kDecompressError);
836866
goto finally;
837867
}
838868

@@ -849,6 +879,8 @@ static PyObject* brotli_decompress(PyObject* self, PyObject* args,
849879

850880
/* Module definition */
851881

882+
static int init_brotli_mod(PyObject* m);
883+
852884
static PyMethodDef brotli_methods[] = {
853885
{"decompress", (PyCFunction)brotli_decompress, METH_VARARGS | METH_KEYWORDS,
854886
brotli_decompress__doc__},
@@ -877,16 +909,29 @@ static PyMethodDef brotli_Decompressor_methods[] = {
877909

878910
#if PY_MAJOR_VERSION >= 3
879911

912+
#if PY_MINOR_VERSION >= 5
913+
static PyModuleDef_Slot brotli_mod_slots[] = {
914+
{Py_mod_exec, init_brotli_mod},
915+
#if PY_MINOR_VERSION >= 12
916+
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
917+
#endif
918+
{0, NULL}};
919+
#endif
920+
880921
static struct PyModuleDef brotli_module = {
881922
PyModuleDef_HEAD_INIT,
882923
"_brotli", /* m_name */
883924
brotli_doc, /* m_doc */
884925
0, /* m_size */
885926
brotli_methods, /* m_methods */
886-
NULL, /* m_reload */
887-
NULL, /* m_traverse */
888-
NULL, /* m_clear */
889-
NULL /* m_free */
927+
#if PY_MINOR_VERSION >= 5
928+
brotli_mod_slots, /* m_slots */
929+
#else
930+
NULL, /* m_reload */
931+
#endif
932+
NULL, /* m_traverse */
933+
NULL, /* m_clear */
934+
NULL /* m_free */
890935
};
891936

892937
static PyType_Slot brotli_Compressor_slots[] = {
@@ -915,6 +960,8 @@ static PyType_Spec brotli_Decompressor_spec = {
915960
"brotli.Decompressor", sizeof(PyBrotli_Decompressor), 0,
916961
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, brotli_Decompressor_slots};
917962

963+
PyMODINIT_FUNC PyInit__brotli(void) { return PyModuleDef_Init(&brotli_module); }
964+
918965
#else
919966

920967
static PyTypeObject brotli_CompressorType = {
@@ -999,18 +1046,11 @@ static PyTypeObject brotli_DecompressorType = {
9991046
brotli_Decompressor_new, /* tp_new */
10001047
};
10011048

1002-
#endif
1049+
PyMODINIT_FUNC init_brotli(void) {
1050+
PyObject* m = Py_InitModule3("_brotli", brotli_methods, brotli_doc);
1051+
(void)init_brotli_mod(m);
1052+
}
10031053

1004-
#if PY_MAJOR_VERSION >= 3
1005-
#define INIT_BROTLI PyInit__brotli
1006-
#define CREATE_BROTLI PyModule_Create(&brotli_module)
1007-
#define RETURN_BROTLI return m
1008-
#define RETURN_NULL return NULL
1009-
#else
1010-
#define INIT_BROTLI init_brotli
1011-
#define CREATE_BROTLI Py_InitModule3("_brotli", brotli_methods, brotli_doc)
1012-
#define RETURN_BROTLI return
1013-
#define RETURN_NULL return
10141054
#endif
10151055

10161056
/* Emulates PyModule_AddObject */
@@ -1027,8 +1067,7 @@ static int RegisterObject(PyObject* mod, const char* name, PyObject* value) {
10271067
#endif
10281068
}
10291069

1030-
PyMODINIT_FUNC INIT_BROTLI(void) {
1031-
PyObject* m = CREATE_BROTLI;
1070+
static int init_brotli_mod(PyObject* m) {
10321071
PyObject* error_type = NULL;
10331072
PyObject* compressor_type = NULL;
10341073
PyObject* decompressor_type = NULL;
@@ -1039,27 +1078,35 @@ PyMODINIT_FUNC INIT_BROTLI(void) {
10391078
brotli_error_doc, NULL, NULL);
10401079
if (error_type == NULL) goto error;
10411080

1042-
if (RegisterObject(m, "error", error_type) < 0) goto error;
1081+
if (RegisterObject(m, kErrorAttr, error_type) < 0) goto error;
1082+
#if PY_MAJOR_VERSION < 3
10431083
/* Assumption: pointer is used only while module is alive and well. */
10441084
BrotliError = error_type;
1085+
#endif
10451086
error_type = NULL;
10461087

10471088
#if PY_MAJOR_VERSION >= 3
10481089
compressor_type = PyType_FromSpec(&brotli_Compressor_spec);
10491090
decompressor_type = PyType_FromSpec(&brotli_Decompressor_spec);
10501091
#else
1051-
compressor_type = &brotli_CompressorType;
1092+
compressor_type = (PyObject*)&brotli_CompressorType;
10521093
Py_INCREF(compressor_type);
1053-
decompressor_type = &brotli_DecompressorType;
1094+
decompressor_type = (PyObject*)&brotli_DecompressorType;
10541095
Py_INCREF(decompressor_type);
10551096
#endif
10561097
if (compressor_type == NULL) goto error;
10571098
if (PyType_Ready((PyTypeObject*)compressor_type) < 0) goto error;
1099+
#if PY_MAJOR_VERSION >= 3
1100+
if (PyObject_SetAttrString(compressor_type, kModuleAttr, m) < 0) goto error;
1101+
#endif
10581102
if (RegisterObject(m, "Compressor", compressor_type) < 0) goto error;
10591103
compressor_type = NULL;
10601104

10611105
if (decompressor_type == NULL) goto error;
10621106
if (PyType_Ready((PyTypeObject*)decompressor_type) < 0) goto error;
1107+
#if PY_MAJOR_VERSION >= 3
1108+
if (PyObject_SetAttrString(decompressor_type, kModuleAttr, m) < 0) goto error;
1109+
#endif
10631110
if (RegisterObject(m, "Decompressor", decompressor_type) < 0) goto error;
10641111
decompressor_type = NULL;
10651112

@@ -1073,7 +1120,7 @@ PyMODINIT_FUNC INIT_BROTLI(void) {
10731120
(decoderVersion >> 12) & 0xFFF, decoderVersion & 0xFFF);
10741121
PyModule_AddStringConstant(m, "__version__", version);
10751122

1076-
RETURN_BROTLI;
1123+
return 0;
10771124

10781125
error:
10791126
if (m != NULL) {
@@ -1092,5 +1139,5 @@ PyMODINIT_FUNC INIT_BROTLI(void) {
10921139
Py_DECREF(decompressor_type);
10931140
decompressor_type = NULL;
10941141
}
1095-
RETURN_NULL;
1142+
return -1;
10961143
}

0 commit comments

Comments
 (0)