diff options
author | Federico Caselli <cfederico87@gmail.com> | 2021-01-01 16:09:01 +0100 |
---|---|---|
committer | Federico Caselli <cfederico87@gmail.com> | 2021-12-17 21:29:05 +0100 |
commit | 76fa211620de167b76846f0e5db5b64b8756ad48 (patch) | |
tree | c435dbf6585b3758dc78ee82bf114e162a25d0e1 /lib/sqlalchemy/cyextension/processors.pyx | |
parent | 3543fcc9c9601e81560d055ceadaea05c75815c0 (diff) | |
download | sqlalchemy-workflow_test_cython.tar.gz |
Replace c extension with cython versions.workflow_test_cython
Re-implement c version immutabledict / processors / resultproxy / utils with cython.
Performance is in general in par or better than the c version
Added a collection module that has cython version of OrderedSet and IdentitySet
Added a new test/perf file to compare the implementations.
Run ``python test/perf/compiled_extensions.py all`` to execute the comparison test.
See results here: https://docs.google.com/document/d/1nOcDGojHRtXEkuy4vNXcW_XOJd9gqKhSeALGG3kYr6A/edit?usp=sharing
Fixes: #7256
Change-Id: I2930ef1894b5048210384728118e586e813f6a76
Signed-off-by: Federico Caselli <cfederico87@gmail.com>
Diffstat (limited to 'lib/sqlalchemy/cyextension/processors.pyx')
-rw-r--r-- | lib/sqlalchemy/cyextension/processors.pyx | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/lib/sqlalchemy/cyextension/processors.pyx b/lib/sqlalchemy/cyextension/processors.pyx new file mode 100644 index 000000000..9f23e73b1 --- /dev/null +++ b/lib/sqlalchemy/cyextension/processors.pyx @@ -0,0 +1,91 @@ +import datetime +import re + +from cpython.datetime cimport date_new, datetime_new, import_datetime, time_new +from cpython.object cimport PyObject_Str +from cpython.unicode cimport PyUnicode_AsASCIIString, PyUnicode_Check, PyUnicode_Decode +from libc.stdio cimport sscanf + + +def int_to_boolean(value): + if value is None: + return None + return True if value else False + +def to_str(value): + return PyObject_Str(value) if value is not None else None + +def to_float(value): + return float(value) if value is not None else None + +cdef inline bytes to_bytes(object value, str type_name): + try: + return PyUnicode_AsASCIIString(value) + except Exception as e: + raise ValueError( + f"Couldn't parse {type_name} string '{value!r}' " + "- value is not a string." + ) from e + +import_datetime() # required to call datetime_new/date_new/time_new + +def str_to_datetime(value): + if value is None: + return None + cdef int numparsed + cdef unsigned int year, month, day, hour, minute, second, microsecond = 0 + cdef bytes value_b = to_bytes(value, 'datetime') + cdef const char * string = value_b + + numparsed = sscanf(string, "%4u-%2u-%2u %2u:%2u:%2u.%6u", + &year, &month, &day, &hour, &minute, &second, µsecond) + if numparsed < 6: + raise ValueError( + "Couldn't parse datetime string: '%s'" % (value) + ) + return datetime_new(year, month, day, hour, minute, second, microsecond, None) + +def str_to_date(value): + if value is None: + return None + cdef int numparsed + cdef unsigned int year, month, day + cdef bytes value_b = to_bytes(value, 'date') + cdef const char * string = value_b + + numparsed = sscanf(string, "%4u-%2u-%2u", &year, &month, &day) + if numparsed != 3: + raise ValueError( + "Couldn't parse date string: '%s'" % (value) + ) + return date_new(year, month, day) + +def str_to_time(value): + if value is None: + return None + cdef int numparsed + cdef unsigned int hour, minute, second, microsecond = 0 + cdef bytes value_b = to_bytes(value, 'time') + cdef const char * string = value_b + + numparsed = sscanf(string, "%2u:%2u:%2u.%6u", &hour, &minute, &second, µsecond) + if numparsed < 3: + raise ValueError( + "Couldn't parse time string: '%s'" % (value) + ) + return time_new(hour, minute, second, microsecond, None) + + +cdef class DecimalResultProcessor: + cdef object type_ + cdef str format_ + + def __cinit__(self, type_, format_): + self.type_ = type_ + self.format_ = format_ + + def process(self, object value): + if value is None: + return None + else: + return self.type_(self.format_ % value) |