Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 1 addition & 7 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -577,12 +577,6 @@ jobs:
- name: Run make install for python
run: sudo make -C lib/py install

# - name: Run make install-exec-hook for python
# run: sudo make -C lib/py install-exec-hook

- name: Run make for python libs
run: make -C lib/py

- name: Run make check for python libs
run: make -C lib/py check

Expand Down Expand Up @@ -842,7 +836,7 @@ jobs:
# kotlin cross test are failing -> see THRIFT-5879
server_lang: ['java', 'go', 'cpp', 'py', 'rb']
# we always use comma join as many client langs as possible, to reduce the number of jobs
client_lang: ['java,kotlin', 'go,cpp', 'py', 'rb']
client_lang: ['java,kotlin', 'go,cpp,py', 'rb']
fail-fast: false
steps:
- uses: actions/checkout@v6
Expand Down
2 changes: 1 addition & 1 deletion LANGUAGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ Thrift's core protocol is TBinary, supported by all languages except for JavaScr
<!-- Since -----------------><td>0.2.0</td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Language Levels -------><td>2.7.12, 3.5.2</td><td>2.7.15, 3.6.8</td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
Expand Down
4 changes: 4 additions & 0 deletions lib/cpp/src/thrift/protocol/TProtocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,10 @@ uint32_t skip(Protocol_& prot, TType type) {
result += prot.readListEnd();
return result;
}
case T_UUID: {
TUuid uuid;
return prot.readUUID(uuid);
}
default:
break;
}
Expand Down
22 changes: 22 additions & 0 deletions lib/py/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ def run_setup(with_binary):
'src/ext/binary.cpp',
'src/ext/compact.cpp',
],
depends=[
'src/ext/binary.h',
'src/ext/compact.h',
'src/ext/endian.h',
'src/ext/protocol.h',
'src/ext/protocol.tcc',
'src/ext/types.h',
],
include_dirs=include_dirs,
)
],
Expand Down Expand Up @@ -138,6 +146,8 @@ def run_setup(with_binary):
try:
with_binary = True
run_setup(with_binary)
sys.exit(0)

except BuildFailed:
print()
print('*' * 80)
Expand All @@ -146,4 +156,16 @@ def run_setup(with_binary):
print('*' * 80)
print()

# Retry but without the binary
try:
run_setup(False)
sys.exit(0)

except BuildFailed:
print()
print('*' * 80)
print("An error occurred while trying to compile without the C extension enabled")
print("Build failed")
print('*' * 80)
print()
sys.exit(1)
6 changes: 2 additions & 4 deletions lib/py/src/Thrift.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ class TType(object):
MAP = 13
SET = 14
LIST = 15
UTF8 = 16
UTF16 = 17
UUID = 16

_VALUES_TO_NAMES = (
'STOP',
Expand All @@ -54,8 +53,7 @@ class TType(object):
'MAP',
'SET',
'LIST',
'UTF8',
'UTF16',
'UUID',
)


Expand Down
12 changes: 12 additions & 0 deletions lib/py/src/ext/binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ class BinaryProtocol : public ProtocolBase<BinaryProtocol> {
return encodeValue(value, parsedspec.type, parsedspec.typeargs);
}

void writeUuid(char* value) {
writeBuffer(value, 16);
}

void writeFieldStop() { writeByte(static_cast<uint8_t>(T_STOP)); }

bool readBool(bool& val) {
Expand Down Expand Up @@ -159,6 +163,13 @@ class BinaryProtocol : public ProtocolBase<BinaryProtocol> {
return len;
}

int32_t readUuid(char** buf) {
if (!readBytes(buf, 16)) {
return -1;
}
return 16;
}

int32_t readListBegin(TType& etype) {
int32_t len;
uint8_t b = 0;
Expand Down Expand Up @@ -206,6 +217,7 @@ class BinaryProtocol : public ProtocolBase<BinaryProtocol> {
}
SKIPBYTES(len);
}
bool skipUuid() { SKIPBYTES(16); }
#undef SKIPBYTES

private:
Expand Down
37 changes: 21 additions & 16 deletions lib/py/src/ext/compact.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,26 @@ namespace apache {
namespace thrift {
namespace py {

/** Mapping of Compact type to Thrift Type according.
* This list must match the TType enum in TEnum.h */
const uint8_t CompactProtocol::TTypeToCType[] = {
CT_STOP, // T_STOP
0, // unused
CT_BOOLEAN_TRUE, // T_BOOL
CT_BYTE, // T_BYTE
CT_DOUBLE, // T_DOUBLE
0, // unused
CT_I16, // T_I16
0, // unused
CT_I32, // T_I32
0, // unused
CT_I64, // T_I64
CT_BINARY, // T_STRING
CT_STRUCT, // T_STRUCT
CT_MAP, // T_MAP
CT_SET, // T_SET
CT_LIST, // T_LIST
/* 0 */ CT_STOP, // T_STOP
/* 1 */ 0, // unused
/* 2 */ CT_BOOLEAN_TRUE, // T_BOOL
/* 3 */ CT_BYTE, // T_BYTE
/* 4 */ CT_DOUBLE, // T_DOUBLE
/* 5 */ 0, // unused
/* 6 */ CT_I16, // T_I16
/* 7 */ 0, // unused
/* 8 */ CT_I32, // T_I32
/* 9 */ 0, // unused
/* 10 */ CT_I64, // T_I64
/* 11 */ CT_BINARY, // T_STRING
/* 12 */ CT_STRUCT, // T_STRUCT
/* 13 */ CT_MAP, // T_MAP
/* 14 */ CT_SET, // T_SET
/* 15 */ CT_LIST, // T_LIST
/* 16 */ CT_UUID, // T_UUID
};

bool CompactProtocol::readFieldBegin(TType& type, int16_t& tag) {
Expand Down Expand Up @@ -98,6 +101,8 @@ TType CompactProtocol::getTType(uint8_t type) {
return T_MAP;
case CT_STRUCT:
return T_STRUCT;
case CT_UUID:
return T_UUID;
default:
PyErr_Format(PyExc_TypeError, "don't know what type: %d", type);
return static_cast<TType>(-1);
Expand Down
19 changes: 17 additions & 2 deletions lib/py/src/ext/compact.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ class CompactProtocol : public ProtocolBase<CompactProtocol> {

void writeFieldStop() { writeByte(0); }

void writeUuid(char* value) {
writeBuffer(value, 16);
}

bool readBool(bool& val) {
if (readBool_.exists) {
readBool_.exists = false;
Expand Down Expand Up @@ -231,6 +235,13 @@ class CompactProtocol : public ProtocolBase<CompactProtocol> {
}
bool readFieldBegin(TType& type, int16_t& tag);

bool readUuid(char** buf) {
if (!readBytes(buf, 16)) {
return false;
}
return true;
}

bool skipBool() {
bool val;
return readBool(val);
Expand Down Expand Up @@ -263,6 +274,9 @@ class CompactProtocol : public ProtocolBase<CompactProtocol> {
}
SKIPBYTES(len);
}
bool skipUuid() {
SKIPBYTES(16);
}
#undef SKIPBYTES

private:
Expand All @@ -279,7 +293,8 @@ class CompactProtocol : public ProtocolBase<CompactProtocol> {
CT_LIST = 0x09,
CT_SET = 0x0A,
CT_MAP = 0x0B,
CT_STRUCT = 0x0C
CT_STRUCT = 0x0C,
CT_UUID = 0x0D,
};

static const uint8_t TTypeToCType[];
Expand All @@ -288,7 +303,7 @@ class CompactProtocol : public ProtocolBase<CompactProtocol> {

int toCompactType(TType type) {
int i = static_cast<int>(type);
return i < 16 ? TTypeToCType[i] : -1;
return i <= 16 ? TTypeToCType[i] : -1;
}

uint32_t toZigZag(int32_t val) { return (val >> 31) ^ (val << 1); }
Expand Down
4 changes: 4 additions & 0 deletions lib/py/src/ext/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
PyObject* INTERN_STRING(TFrozenDict);
PyObject* INTERN_STRING(cstringio_buf);
PyObject* INTERN_STRING(cstringio_refill);
PyObject* INTERN_STRING(UUID);
PyObject* INTERN_STRING(bytes);
static PyObject* INTERN_STRING(string_length_limit);
static PyObject* INTERN_STRING(container_length_limit);
static PyObject* INTERN_STRING(trans);
Expand Down Expand Up @@ -186,6 +188,8 @@ void initfastbinary() {
INIT_INTERN_STRING(string_length_limit);
INIT_INTERN_STRING(container_length_limit);
INIT_INTERN_STRING(trans);
INIT_INTERN_STRING(UUID);
INIT_INTERN_STRING(bytes);
#undef INIT_INTERN_STRING

PyObject* module =
Expand Down
56 changes: 50 additions & 6 deletions lib/py/src/ext/protocol.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -542,10 +542,27 @@ bool ProtocolBase<Impl>::encodeValue(PyObject* value, TType type, PyObject* type
return true;
}

case T_UUID: {
ScopedPyObject instval(PyObject_GetAttr(value, INTERN_STRING(bytes)));
if (!instval) {
return false;
}

Py_ssize_t size;
char* buffer;
if (PyBytes_AsStringAndSize(instval.get(), &buffer, &size) < 0) {
return false;
}
if (size != 16) {
PyErr_SetString(PyExc_TypeError, "uuid.bytes must be exactly 16 bytes long");
return false;
}
impl()->writeUuid(buffer);
return true;
}

case T_STOP:
case T_VOID:
case T_UTF16:
case T_UTF8:
case T_U64:
default:
PyErr_Format(PyExc_TypeError, "Unexpected TType for encodeValue: %d", type);
Expand Down Expand Up @@ -625,11 +642,12 @@ bool ProtocolBase<Impl>::skip(TType type) {
}
return true;
}
case T_UUID: {
return impl()->skipUuid();
}

case T_STOP:
case T_VOID:
case T_UTF16:
case T_UTF8:
case T_U64:
default:
PyErr_Format(PyExc_TypeError, "Unexpected TType for skip: %d", type);
Expand Down Expand Up @@ -816,10 +834,36 @@ PyObject* ProtocolBase<Impl>::decodeValue(TType type, PyObject* typeargs) {
return readStruct(Py_None, parsedargs.klass, parsedargs.spec);
}

case T_UUID: {
char* buf = nullptr;
if(!impl()->readUuid(&buf)) {
return nullptr;
}

if(!UuidModule) {
UuidModule = PyImport_ImportModule("uuid");
if (!UuidModule)
return nullptr;
}

ScopedPyObject cls(PyObject_GetAttr(UuidModule, INTERN_STRING(UUID)));
if (!cls) {
return nullptr;
}

ScopedPyObject pyBytes(PyBytes_FromStringAndSize(buf, 16));
if (!pyBytes) {
return nullptr;
}

ScopedPyObject args(PyTuple_New(0));
ScopedPyObject kwargs(Py_BuildValue("{O:O}", INTERN_STRING(bytes), pyBytes.get()));
ScopedPyObject ret(PyObject_Call(cls.get(), args.get(), kwargs.get()));
return ret.release();
}

case T_STOP:
case T_VOID:
case T_UTF16:
case T_UTF8:
case T_U64:
default:
PyErr_Format(PyExc_TypeError, "Unexpected TType for decodeValue: %d", type);
Expand Down
1 change: 1 addition & 0 deletions lib/py/src/ext/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace thrift {
namespace py {

PyObject* ThriftModule = nullptr;
PyObject* UuidModule = nullptr;

#if PY_MAJOR_VERSION < 3
char refill_signature[] = {'s', '#', 'i'};
Expand Down
6 changes: 4 additions & 2 deletions lib/py/src/ext/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,16 @@ extern "C" {
extern PyObject* INTERN_STRING(TFrozenDict);
extern PyObject* INTERN_STRING(cstringio_buf);
extern PyObject* INTERN_STRING(cstringio_refill);
extern PyObject* INTERN_STRING(UUID);
extern PyObject* INTERN_STRING(bytes);
}

namespace apache {
namespace thrift {
namespace py {

extern PyObject* ThriftModule;
extern PyObject* UuidModule;

// Stolen out of TProtocol.h.
// It would be a huge pain to have both get this from one place.
Expand All @@ -76,8 +79,7 @@ enum TType {
T_MAP = 13,
T_SET = 14,
T_LIST = 15,
T_UTF8 = 16,
T_UTF16 = 17
T_UUID = 16,
};

// replace with unique_ptr when we're OK with C++11
Expand Down
Loading