diff options
Diffstat (limited to 'cython')
-rw-r--r-- | cython/CMakeLists.txt | 30 | ||||
-rw-r--r-- | cython/plist.pxd | 62 | ||||
-rw-r--r-- | cython/plist.pyx | 699 | ||||
-rw-r--r-- | cython/plist_util.c | 41 | ||||
-rw-r--r-- | cython/plist_util.h | 5 |
5 files changed, 837 insertions, 0 deletions
diff --git a/cython/CMakeLists.txt b/cython/CMakeLists.txt new file mode 100644 index 0000000..eac6bee --- /dev/null +++ b/cython/CMakeLists.txt @@ -0,0 +1,30 @@ + +INCLUDE_DIRECTORIES( ${PYTHON_INCLUDE_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ) + + +SET(plist_SRC + ${CMAKE_CURRENT_BINARY_DIR}/plist.c ) + +SET(plist_HDR + ${CMAKE_CURRENT_SOURCE_DIR}/plist.pxd ) + +ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/plist.c + COMMAND ${CYTHON_EXECUTABLE} -o ${CMAKE_CURRENT_BINARY_DIR}/plist.c ${CMAKE_CURRENT_SOURCE_DIR}/plist.pyx + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/plist.pyx ${CMAKE_CURRENT_SOURCE_DIR}/plist.pxd +) + + +EXEC_PROGRAM("${PYTHON_EXECUTABLE}" + ARGS "-c 'try:\n import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1,0,\"${CMAKE_INSTALL_PREFIX}\")\nexcept: pass\n'" + OUTPUT_VARIABLE DISTUTILS_PYTHON_ILIBRARY_PATH + ) + +PYTHON_ADD_MODULE(cython_plist plist.c plist_util.c) +SET_TARGET_PROPERTIES(cython_plist PROPERTIES PREFIX "" OUTPUT_NAME plist) +TARGET_LINK_LIBRARIES(cython_plist plist ${PYTHON_LIBRARIES}) + +INSTALL( FILES ${CMAKE_CURRENT_BINARY_DIR}/plist${CMAKE_SHARED_MODULE_SUFFIX} + DESTINATION ${DISTUTILS_PYTHON_ILIBRARY_PATH} ) +INSTALL( FILES ${CMAKE_CURRENT_SOURCE_DIR}/plist.pxd + DESTINATION include/plist/cython COMPONENT dev) diff --git a/cython/plist.pxd b/cython/plist.pxd new file mode 100644 index 0000000..daafd78 --- /dev/null +++ b/cython/plist.pxd @@ -0,0 +1,62 @@ +cdef extern from "plist/plist.h": + ctypedef void *plist_t + ctypedef void *plist_dict_iter + +cdef class Node: + cdef plist_t _c_node + cdef bool _c_managed + cpdef object __deepcopy__(self, memo=*) + cpdef bytes to_xml(self) + cpdef bytes to_bin(self) + cpdef object copy(self) + +cdef class Bool(Node): + cpdef set_value(self, value) + cpdef bool get_value(self) + +cdef class Integer(Node): + cpdef set_value(self, value) + cpdef int get_value(self) + +cdef class Real(Node): + cpdef set_value(self, value) + cpdef float get_value(self) + +cdef class String(Node): + cpdef set_value(self, unicode value) + cpdef unicode get_value(self) + +cdef class Date(Node): + cpdef set_value(self, value) + cpdef object get_value(self) + +cdef class Data(Node): + cpdef set_value(self, bytes value) + cpdef bytes get_value(self) + +cdef class Dict(Node): + cdef dict _map + cdef void _init(self) + cpdef set_value(self, dict value) + cpdef dict get_value(self) + cpdef bool has_key(self, key) + cpdef object get(self, key, default=*) + cpdef list keys(self) + cpdef list items(self) + cpdef list values(self) + cpdef object iterkeys(self) + cpdef object iteritems(self) + cpdef object itervalues(self) + +cdef class Array(Node): + cdef list _array + cdef void _init(self) + cpdef set_value(self, value) + cpdef list get_value(self) + cpdef append(self, item) + +cpdef object from_xml(xml) +cpdef object from_bin(bytes bin) + +cdef object plist_t_to_node(plist_t c_plist, bool managed=*) +cdef plist_t native_to_plist_t(object native) diff --git a/cython/plist.pyx b/cython/plist.pyx new file mode 100644 index 0000000..a1282e7 --- /dev/null +++ b/cython/plist.pyx @@ -0,0 +1,699 @@ +cdef extern from *: + ctypedef unsigned char uint8_t + ctypedef short int int16_t + ctypedef unsigned short int uint16_t + ctypedef unsigned int uint32_t + ctypedef int int32_t +IF UNAME_MACHINE == 'x86_64': + ctypedef unsigned long int uint64_t +ELSE: + ctypedef unsigned long long int uint64_t + +cimport python_unicode + +cdef extern from *: + ctypedef enum plist_type: + PLIST_BOOLEAN, + PLIST_UINT, + PLIST_REAL, + PLIST_STRING, + PLIST_ARRAY, + PLIST_DICT, + PLIST_DATE, + PLIST_DATA, + PLIST_KEY, + PLIST_NONE + + plist_t plist_new_bool(uint8_t val) + void plist_get_bool_val(plist_t node, uint8_t *val) + void plist_set_bool_val(plist_t node, uint8_t val) + + plist_t plist_new_uint(uint64_t val) + void plist_get_uint_val(plist_t node, uint64_t *val) + void plist_set_uint_val(plist_t node, uint64_t val) + + plist_t plist_new_real(double val) + void plist_get_real_val(plist_t node, double *val) + void plist_set_real_val(plist_t node, double val) + + plist_t plist_new_date(int32_t sec, int32_t usec) + void plist_get_date_val(plist_t node, int32_t * sec, int32_t * usec) + void plist_set_date_val(plist_t node, int32_t sec, int32_t usec) + + plist_t plist_new_string(char *val) + void plist_get_string_val(plist_t node, char **val) + void plist_set_string_val(plist_t node, char *val) + + plist_t plist_new_data(char *val, uint64_t length) + void plist_get_data_val(plist_t node, char **val, uint64_t * length) + void plist_set_data_val(plist_t node, char *val, uint64_t length) + + plist_t plist_new_dict() + int plist_dict_get_size(plist_t node) + plist_t plist_dict_get_item(plist_t node, char* key) + void plist_dict_set_item(plist_t node, char* key, plist_t item) + void plist_dict_insert_item(plist_t node, char* key, plist_t item) + void plist_dict_remove_item(plist_t node, char* key) + + void plist_dict_new_iter(plist_t node, plist_dict_iter *iter) + void plist_dict_next_item(plist_t node, plist_dict_iter iter, char **key, plist_t *val) + + plist_t plist_new_array() + uint32_t plist_array_get_size(plist_t node) + plist_t plist_array_get_item(plist_t node, uint32_t n) + uint32_t plist_array_get_item_index(plist_t node) + void plist_array_set_item(plist_t node, plist_t item, uint32_t n) + void plist_array_append_item(plist_t node, plist_t item) + void plist_array_insert_item(plist_t node, plist_t item, uint32_t n) + void plist_array_remove_item(plist_t node, uint32_t n) + + void plist_free(plist_t plist) + plist_t plist_copy(plist_t plist) + void plist_to_xml(plist_t plist, char **plist_xml, uint32_t *length) + void plist_to_bin(plist_t plist, char **plist_bin, uint32_t *length) + + plist_t plist_get_parent(plist_t node) + plist_type plist_get_node_type(plist_t node) + + void plist_set_type(plist_t node, plist_type type) + + void plist_from_xml(char *plist_xml, uint32_t length, plist_t * plist) + void plist_from_bin(char *plist_bin, uint32_t length, plist_t * plist) + +cdef extern from *: + void free(void *ptr) + +cdef class Node: + def __init__(self, *args, **kwargs): + self._c_managed = True + + def __dealloc__(self): + if self._c_node is not NULL and self._c_managed: + plist_free(self._c_node) + + cpdef object __deepcopy__(self, memo={}): + return plist_t_to_node(plist_copy(self._c_node)) + + cpdef object copy(self): + cdef plist_t c_node = NULL + c_node = plist_copy(self._c_node) + return plist_t_to_node(c_node) + + cpdef bytes to_xml(self): + cdef char* out = NULL + cdef uint32_t length + plist_to_xml(self._c_node, &out, &length) + + return out[:length] + + cpdef bytes to_bin(self): + cdef char* out = NULL + cdef uint32_t length + plist_to_bin(self._c_node, &out, &length) + + return out[:length] + + property parent: + def __get__(self): + cdef plist_t c_parent = NULL + cdef Node node + + c_parent = plist_get_parent(self._c_node) + if c_parent == NULL: + return None + + return plist_t_to_node(c_parent) + + def __str__(self): + return str(self.get_value()) + +cdef class Bool(Node): + def __cinit__(self, value=None, *args, **kwargs): + if value is None: + self._c_node = plist_new_bool(0) + else: + self._c_node = plist_new_bool(bool(value)) + + def __nonzero__(self): + return self.get_value() + + def __richcmp__(self, other, op): + cdef bool b = self.get_value() + if op == 0: + return b < other + if op == 1: + return b <= other + if op == 2: + return b == other + if op == 3: + return b != other + if op == 4: + return b > other + if op == 5: + return b >= other + + def __repr__(self): + b = self.get_value() + return '<Bool: %s>' % b + + cpdef set_value(self, value): + plist_set_bool_val(self._c_node, bool(value)) + + cpdef bool get_value(self): + cdef uint8_t value + plist_get_bool_val(self._c_node, &value) + return bool(value) + +cdef Bool Bool_factory(plist_t c_node, bool managed=True): + cdef Bool instance = Bool.__new__(Bool) + instance._c_managed = managed + instance._c_node = c_node + return instance + +cdef class Integer(Node): + def __cinit__(self, value=None, *args, **kwargs): + if value is None: + self._c_node = plist_new_uint(0) + else: + self._c_node = plist_new_uint(int(value)) + + def __repr__(self): + i = self.get_value() + return '<Integer: %s>' % i + + def __int__(self): + return self.get_value() + + def __float__(self): + return float(self.get_value()) + + def __richcmp__(self, other, op): + cdef int i = self.get_value() + if op == 0: + return i < other + if op == 1: + return i <= other + if op == 2: + return i == other + if op == 3: + return i != other + if op == 4: + return i > other + if op == 5: + return i >= other + + cpdef set_value(self, value): + plist_set_uint_val(self._c_node, int(value)) + + cpdef int get_value(self): + cdef uint64_t value + plist_get_uint_val(self._c_node, &value) + return value + +cdef Integer Integer_factory(plist_t c_node, bool managed=True): + cdef Integer instance = Integer.__new__(Integer) + instance._c_managed = managed + instance._c_node = c_node + return instance + +cdef class Real(Node): + def __cinit__(self, value=None, *args, **kwargs): + if value is None: + self._c_node = plist_new_real(0.0) + else: + self._c_node = plist_new_real(float(value)) + + def __repr__(self): + r = self.get_value() + return '<Real: %s>' % r + + def __float__(self): + return self.get_value() + + def __int__(self): + return int(self.get_value()) + + def __richcmp__(self, other, op): + cdef float f = self.get_value() + if op == 0: + return f < other + if op == 1: + return f <= other + if op == 2: + return f == other + if op == 3: + return f != other + if op == 4: + return f > other + if op == 5: + return f >= other + + cpdef set_value(self, value): + plist_set_real_val(self._c_node, float(value)) + + cpdef float get_value(self): + cdef double value + plist_get_real_val(self._c_node, &value) + return value + +cdef Real Real_factory(plist_t c_node, bool managed=True): + cdef Real instance = Real.__new__(Real) + instance._c_managed = managed + instance._c_node = c_node + return instance + +from python_version cimport PY_MAJOR_VERSION + +cdef class String(Node): + def __cinit__(self, value=None, *args, **kwargs): + if value is None: + self._c_node = plist_new_string("") + else: + if isinstance(value, unicode): + utf8_data = value.encode('utf-8') + elif (PY_MAJOR_VERSION < 3) and isinstance(value, str): + value.decode('ascii') + utf8_data = value + else: + raise ValueError("requires text input, got %s" % type(value)) + self._c_node = plist_new_string(utf8_data) + + def __repr__(self): + s = self.get_value() + return '<String: %s>' % s + + def __richcmp__(self, other, op): + cdef str s = self.get_value() + if op == 0: + return s < other + if op == 1: + return s <= other + if op == 2: + return s == other + if op == 3: + return s != other + if op == 4: + return s > other + if op == 5: + return s >= other + + cpdef set_value(self, unicode value): + if value is None: + self._c_node = plist_new_string("") + else: + if isinstance(value, unicode): + utf8_data = value.encode('utf-8') + elif (PY_MAJOR_VERSION < 3) and isinstance(value, str): + value.decode('ascii') + utf8_data = value + else: + raise ValueError("requires text input, got %s" % type(value)) + self._c_node = plist_new_string(utf8_data) + + cpdef unicode get_value(self): + cdef char* value = NULL + plist_get_string_val(self._c_node, &value) + return python_unicode.PyUnicode_DecodeUTF8(value, len(value), 'strict') + +cdef String String_factory(plist_t c_node, bool managed=True): + cdef String instance = String.__new__(String) + instance._c_managed = managed + instance._c_node = c_node + return instance + +cdef extern from "plist_util.h": + void datetime_to_ints(object obj, int32_t* sec, int32_t* usec) + object ints_to_datetime(int32_t sec, int32_t usec) + int check_datetime(object obj) + +cdef plist_t create_date_plist(value=None): + cdef plist_t node = NULL + cdef int32_t secs + cdef int32_t usecs + if value is None: + node = plist_new_date(0, 0) + elif check_datetime(value): + datetime_to_ints(value, &secs, &usecs) + node = plist_new_date(secs, usecs) + return node + +cdef class Date(Node): + def __cinit__(self, value=None, *args, **kwargs): + self._c_node = create_date_plist(value) + + def __repr__(self): + d = self.get_value() + return '<Date: %s>' % d.ctime() + + def __richcmp__(self, other, op): + d = self.get_value() + if op == 0: + return d < other + if op == 1: + return d <= other + if op == 2: + return d == other + if op == 3: + return d != other + if op == 4: + return d > other + if op == 5: + return d >= other + + cpdef object get_value(self): + cdef int32_t secs = 0 + cdef int32_t usecs = 0 + cdef object result + plist_get_date_val(self._c_node, &secs, &usecs) + return ints_to_datetime(secs, usecs) + + cpdef set_value(self, value): + cdef int32_t secs + cdef int32_t usecs + if not check_datetime(value): + raise ValueError("Expected a datetime") + datetime_to_ints(value, &secs, &usecs) + plist_set_date_val(self._c_node, secs, usecs) + +cdef Date Date_factory(plist_t c_node, bool managed=True): + cdef Date instance = Date.__new__(Date) + instance._c_managed = managed + instance._c_node = c_node + return instance + +cdef class Data(Node): + def __cinit__(self, value=None, *args, **kwargs): + if value is None: + self._c_node = plist_new_data(NULL, 0) + else: + self._c_node = plist_new_data(value, len(value)) + + def __repr__(self): + d = self.get_value() + return '<Data: %s>' % d + + def __richcmp__(self, other, op): + cdef str d = self.get_value() + if op == 0: + return d < other + if op == 1: + return d <= other + if op == 2: + return d == other + if op == 3: + return d != other + if op == 4: + return d > other + if op == 5: + return d >= other + + cpdef bytes get_value(self): + cdef char* val = NULL + cdef uint64_t length = 0 + plist_get_data_val(self._c_node, &val, &length) + + return val[:length] + + cpdef set_value(self, bytes value): + plist_set_data_val(self._c_node, value, len(value)) + +cdef Data Data_factory(plist_t c_node, bool managed=True): + cdef Data instance = Data.__new__(Data) + instance._c_managed = managed + instance._c_node = c_node + return instance + +cdef plist_t create_dict_plist(value=None): + cdef plist_t node = NULL + cdef plist_t c_node = NULL + node = plist_new_dict() + if value is not None and isinstance(value, dict): + for key, item in value.items(): + c_node = native_to_plist_t(item) + plist_dict_insert_item(node, key, c_node) + c_node = NULL + return node + +cdef class Dict(Node): + def __cinit__(self, value=None, *args, **kwargs): + self._c_node = create_dict_plist(value) + + def __init__(self, value=None, *args, **kwargs): + self._init() + + cdef void _init(self): + cdef plist_dict_iter it = NULL + cdef char* key = NULL + cdef plist_t subnode = NULL + + self._map = {} + + plist_dict_new_iter(self._c_node, &it); + plist_dict_next_item(self._c_node, it, &key, &subnode); + + while subnode is not NULL: + self._map[key] = plist_t_to_node(subnode, False) + subnode = NULL + free(key) + key = NULL + plist_dict_next_item(self._c_node, it, &key, &subnode); + free(it) + + def __dealloc__(self): + self._map = None + Node.__dealloc__(self) + + def __richcmp__(self, other, op): + cdef dict d = self.get_value() + if op == 0: + return d < other + if op == 1: + return d <= other + if op == 2: + return d == other + if op == 3: + return d != other + if op == 4: + return d > other + if op == 5: + return d >= other + + def __len__(self): + return len(self._map) + + def __repr__(self): + return '<Dict: %s>' % self._map + + cpdef dict get_value(self): + return dict([(key, value.get_value()) for key, value in self.items()]) + + cpdef set_value(self, dict value): + plist_free(self._c_node) + self._map = {} + self._c_node = NULL + self._c_node = create_dict_plist(value) + self._init() + + def __iter__(self): + return self._map.__iter__() + + cpdef bool has_key(self, key): + return self._map.has_key(key) + + cpdef object get(self, key, default=None): + return self._map.get(key, default) + + cpdef list keys(self): + return self._map.keys() + + cpdef object iterkeys(self): + return self._map.iterkeys() + + cpdef list items(self): + return self._map.items() + + cpdef object iteritems(self): + return self._map.iteritems() + + cpdef list values(self): + return self._map.values() + + cpdef object itervalues(self): + return self._map.itervalues() + + def __getitem__(self, key): + return self._map[key] + + def __setitem__(self, key, value): + cdef Node n + if isinstance(value, Node): + n = value.copy() + else: + n = plist_t_to_node(native_to_plist_t(value), False) + + plist_dict_insert_item(self._c_node, key, n._c_node) + self._map[key] = n + + def __delitem__(self, key): + del self._map[key] + plist_dict_remove_item(self._c_node, key) + +cdef Dict Dict_factory(plist_t c_node, bool managed=True): + cdef Dict instance = Dict.__new__(Dict) + instance._c_managed = managed + instance._c_node = c_node + instance._init() + return instance + +cdef plist_t create_array_plist(value=None): + cdef plist_t node = NULL + cdef plist_t c_node = NULL + node = plist_new_array() + if value is not None and (isinstance(value, list) or isinstance(value, tuple)): + for item in value: + c_node = native_to_plist_t(item) + plist_array_append_item(node, c_node) + c_node = NULL + return node + +cdef class Array(Node): + def __cinit__(self, value=None, *args, **kwargs): + self._c_node = create_array_plist(value) + + def __init__(self, value=None, *args, **kwargs): + self._init() + + cdef void _init(self): + cdef uint32_t size = plist_array_get_size(self._c_node) + cdef plist_t subnode = NULL + + for i from 0 <= i < size: + subnode = plist_array_get_item(self._c_node, i) + self._array.append(plist_t_to_node(subnode, False)) + + def __richcmp__(self, other, op): + cdef list l = self.get_value() + if op == 0: + return l < other + if op == 1: + return l <= other + if op == 2: + return l == other + if op == 3: + return l != other + if op == 4: + return l > other + if op == 5: + return l >= other + + def __len__(self): + return len(self._array) + + def __repr__(self): + return '<Array: %s>' % self._array + + cpdef list get_value(self): + return [i.get_value() for i in self] + + cpdef set_value(self, value): + self._array = [] + plist_free(self._c_node) + self._c_node = NULL + self._c_node = create_array_plist(value) + self._init() + + def __iter__(self): + return self._array.__iter__() + + def __getitem__(self, index): + return self._array[index] + + def __setitem__(self, index, value): + cdef Node n + if isinstance(value, Node): + n = value.copy() + else: + n = plist_t_to_node(native_to_plist_t(value), False) + + if index < 0: + index = len(self) + index + + plist_array_set_item(self._c_node, n._c_node, index) + self._array[index] = n + + def __delitem__(self, index): + if index < 0: + index = len(self) + index + del self._array[index] + plist_array_remove_item(self._c_node, index) + + cpdef append(self, item): + cdef Node n + + if isinstance(item, Node): + n = item.copy() + else: + n = plist_t_to_node(native_to_plist_t(item), False) + + plist_array_append_item(self._c_node, n._c_node) + self._array.append(n) + +cdef Array Array_factory(plist_t c_node, bool managed=True): + cdef Array instance = Array.__new__(Array) + instance._c_managed = managed + instance._c_node = c_node + instance._init() + return instance + +cpdef object from_xml(xml): + cdef plist_t c_node = NULL + plist_from_xml(xml, len(xml), &c_node) + return plist_t_to_node(c_node) + +cpdef object from_bin(bytes bin): + cdef plist_t c_node = NULL + plist_from_bin(bin, len(bin), &c_node) + return plist_t_to_node(c_node) + +cdef plist_t native_to_plist_t(object native): + cdef plist_t c_node + cdef plist_t child_c_node + cdef int32_t secs = 0 + cdef int32_t usecs = 0 + cdef Node node + if isinstance(native, Node): + node = native + return plist_copy(node._c_node) + if isinstance(native, basestring): + return plist_new_string(native) + if isinstance(native, bool): + return plist_new_bool(native) + if isinstance(native, int) or isinstance(native, long): + return plist_new_uint(native) + if isinstance(native, float): + return plist_new_real(native) + if isinstance(native, dict): + return create_dict_plist(native) + if isinstance(native, list) or isinstance(native, tuple): + return create_array_plist(native) + if check_datetime(native): + return create_date_plist(native) + +cdef object plist_t_to_node(plist_t c_plist, bool managed=True): + cdef plist_type t = plist_get_node_type(c_plist) + if t == PLIST_BOOLEAN: + return Bool_factory(c_plist, managed) + if t == PLIST_UINT: + return Integer_factory(c_plist, managed) + if t == PLIST_REAL: + return Real_factory(c_plist, managed) + if t == PLIST_STRING: + return String_factory(c_plist, managed) + if t == PLIST_ARRAY: + return Array_factory(c_plist, managed) + if t == PLIST_DICT: + return Dict_factory(c_plist, managed) + if t == PLIST_DATE: + return Date_factory(c_plist, managed) + if t == PLIST_DATA: + return Data_factory(c_plist, managed) diff --git a/cython/plist_util.c b/cython/plist_util.c new file mode 100644 index 0000000..70c5be3 --- /dev/null +++ b/cython/plist_util.c @@ -0,0 +1,41 @@ +#include "plist_util.h" + +#include <time.h> +#include <datetime.h> + +void datetime_to_ints(PyObject* obj, int32_t* sec, int32_t* usec) { + PyDateTime_IMPORT; + if (!PyDateTime_Check(obj)) { + PyErr_SetString(PyExc_ValueError,"Expected a datetime"); + sec = NULL; + usec = NULL; + return; + } + struct tm t = { + PyDateTime_DATE_GET_SECOND(obj), + PyDateTime_DATE_GET_MINUTE(obj), + PyDateTime_DATE_GET_HOUR(obj), + PyDateTime_GET_DAY(obj), + PyDateTime_GET_MONTH(obj)-1, + PyDateTime_GET_YEAR(obj)-1900, + 0,0,0 + }; + *sec = (int32_t)mktime(&t); + *usec = PyDateTime_DATE_GET_MICROSECOND(obj); +} +PyObject* ints_to_datetime(int32_t sec, int32_t usec) { + time_t sec_tt = sec; + struct tm* t = gmtime(&sec_tt); + if(t){ + PyDateTime_IMPORT; + return PyDateTime_FromDateAndTime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, usec); + } + return NULL; +} +int check_datetime(PyObject* ob) { + if(ob){ + PyDateTime_IMPORT; + return PyDateTime_Check(ob); + } + return 0; +} diff --git a/cython/plist_util.h b/cython/plist_util.h new file mode 100644 index 0000000..fbf56b6 --- /dev/null +++ b/cython/plist_util.h @@ -0,0 +1,5 @@ +#include <Python.h> + +void datetime_to_ints(PyObject* obj, int32_t* sec, int32_t* usec); +PyObject* ints_to_datetime(int32_t sec, int32_t usec); +int check_datetime(PyObject* obj); |