PYTHON-1213 - Make decimal128 work with cdecimal

This commit is contained in:
Bernie Hackett 2017-04-04 13:08:21 -07:00
parent a426aef599
commit 02e606608e
4 changed files with 114 additions and 4 deletions

View File

@ -345,6 +345,15 @@ functions:
${PREPARE_SHELL}
PYTHON_BINARY=${PYTHON_BINARY} PROJECT_DIRECTORY=${PROJECT_DIRECTORY} sh ${PROJECT_DIRECTORY}/.evergreen/run-mockupdb-tests.sh
"run cdecimal tests":
- command: shell.exec
type: test
params:
working_dir: "src"
script: |
${PREPARE_SHELL}
PYTHON_BINARY=${PYTHON_BINARY} sh ${PROJECT_DIRECTORY}/.evergreen/run-cdecimal-tests.sh
"run doctests":
- command: shell.exec
type: test
@ -681,6 +690,15 @@ tasks:
TOPOLOGY: "replica_set"
- func: "run mod_wsgi tests"
- name: "cdecimal"
tags: ["cdecimal"]
commands:
- func: "bootstrap mongo-orchestration"
vars:
VERSION: "latest"
TOPOLOGY: "server"
- func: "run cdecimal tests"
# }}}
@ -1316,6 +1334,15 @@ buildvariants:
tasks:
- name: "doctests"
- matrix_name: "cdecimal"
matrix_spec: {python-version: ["2.6", "2.7"]}
display_name: "cdecimal ${python-version}"
batchtime: 10080 # 7 days
run_on:
- ubuntu1604-test
tasks:
- name: "cdecimal"
# Platform notes
# i386 builds of OpenSSL or Cyrus SASL are not available
# Ubuntu14.04 only supports 2.6+ with SSL

View File

@ -0,0 +1,12 @@
#!/bin/bash
set -o xtrace
set -o errexit
virtualenv -p ${PYTHON_BINARY} cdecimaltest
trap "deactivate; rm -rf cdecimaltest" EXIT HUP
. cdecimaltest/bin/activate
# No cdecimal tarballs on pypi.
pip install http://www.bytereef.org/software/mpdecimal/releases/cdecimal-2.3.tar.gz
python -c 'import sys; print(sys.version)'
python cdecimal_test.py

View File

@ -84,9 +84,12 @@ _CTX_OPTIONS = {
decimal.Inexact]
}
if _PY3:
try:
# Python >= 3.3, cdecimal
decimal.Context(clamp=1) # pylint: disable=unexpected-keyword-arg
_CTX_OPTIONS['clamp'] = 1
else:
except TypeError:
# Python < 3.3
_CTX_OPTIONS['_clamp'] = 1
_DEC128_CTX = decimal.Context(**_CTX_OPTIONS.copy())
@ -273,7 +276,7 @@ class Decimal128(object):
elif (high & _NAN) == _NAN:
return decimal.Decimal((sign, (), 'n'))
elif (high & _INF) == _INF:
return decimal.Decimal((sign, (0,), 'F'))
return decimal.Decimal((sign, (), 'F'))
if (high & _EXPONENT_MASK) == _EXPONENT_MASK:
exponent = ((high & 0x1fffe00000000000) >> 47) - _EXPONENT_BIAS
@ -296,7 +299,9 @@ class Decimal128(object):
arr[0] = (high & mask) >> 48
# Have to convert bytearray to bytes for python 2.6.
digits = [int(digit) for digit in str(_from_bytes(bytes(arr), 'big'))]
# cdecimal only accepts a tuple for digits.
digits = tuple(
int(digit) for digit in str(_from_bytes(bytes(arr), 'big')))
with decimal.localcontext(_DEC128_CTX) as ctx:
return ctx.create_decimal((sign, digits, exponent))

66
cdecimal_test.py Normal file
View File

@ -0,0 +1,66 @@
# Copyright 2017 MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Test PyMongo with cdecimal monkey-patched over stdlib decimal."""
import getopt
import sys
try:
import cdecimal
_HAVE_CDECIMAL = True
except ImportError:
_HAVE_CDECIMAL = False
def run(args):
"""Run tests with cdecimal monkey-patched over stdlib decimal."""
# Monkey-patch.
sys.modules['decimal'] = cdecimal
# Run the tests.
sys.argv[:] = ['setup.py', 'test'] + list(args)
import setup
def main():
"""Parse options and run tests."""
usage = """python %s
Test PyMongo with cdecimal monkey-patched over decimal.""" % (sys.argv[0],)
try:
opts, args = getopt.getopt(
sys.argv[1:], "h", ["help"])
except getopt.GetoptError as err:
print(str(err))
print(usage)
sys.exit(2)
for option_name, _ in opts:
if option_name in ("-h", "--help"):
print(usage)
sys.exit()
else:
assert False, "unhandled option"
if not _HAVE_CDECIMAL:
print("The cdecimal package is not installed.")
sys.exit(1)
run(args) # Command line args to setup.py, like what test to run.
if __name__ == '__main__':
main()