Skip to content

Commit 02e6066

Browse files
committed
PYTHON-1213 - Make decimal128 work with cdecimal
1 parent a426aef commit 02e6066

File tree

4 files changed

+114
-4
lines changed

4 files changed

+114
-4
lines changed

.evergreen/config.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,15 @@ functions:
345345
${PREPARE_SHELL}
346346
PYTHON_BINARY=${PYTHON_BINARY} PROJECT_DIRECTORY=${PROJECT_DIRECTORY} sh ${PROJECT_DIRECTORY}/.evergreen/run-mockupdb-tests.sh
347347
348+
"run cdecimal tests":
349+
- command: shell.exec
350+
type: test
351+
params:
352+
working_dir: "src"
353+
script: |
354+
${PREPARE_SHELL}
355+
PYTHON_BINARY=${PYTHON_BINARY} sh ${PROJECT_DIRECTORY}/.evergreen/run-cdecimal-tests.sh
356+
348357
"run doctests":
349358
- command: shell.exec
350359
type: test
@@ -681,6 +690,15 @@ tasks:
681690
TOPOLOGY: "replica_set"
682691
- func: "run mod_wsgi tests"
683692

693+
- name: "cdecimal"
694+
tags: ["cdecimal"]
695+
commands:
696+
- func: "bootstrap mongo-orchestration"
697+
vars:
698+
VERSION: "latest"
699+
TOPOLOGY: "server"
700+
- func: "run cdecimal tests"
701+
684702
# }}}
685703

686704

@@ -1316,6 +1334,15 @@ buildvariants:
13161334
tasks:
13171335
- name: "doctests"
13181336

1337+
- matrix_name: "cdecimal"
1338+
matrix_spec: {python-version: ["2.6", "2.7"]}
1339+
display_name: "cdecimal ${python-version}"
1340+
batchtime: 10080 # 7 days
1341+
run_on:
1342+
- ubuntu1604-test
1343+
tasks:
1344+
- name: "cdecimal"
1345+
13191346
# Platform notes
13201347
# i386 builds of OpenSSL or Cyrus SASL are not available
13211348
# Ubuntu14.04 only supports 2.6+ with SSL

.evergreen/run-cdecimal-tests.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
3+
set -o xtrace
4+
set -o errexit
5+
6+
virtualenv -p ${PYTHON_BINARY} cdecimaltest
7+
trap "deactivate; rm -rf cdecimaltest" EXIT HUP
8+
. cdecimaltest/bin/activate
9+
# No cdecimal tarballs on pypi.
10+
pip install http://www.bytereef.org/software/mpdecimal/releases/cdecimal-2.3.tar.gz
11+
python -c 'import sys; print(sys.version)'
12+
python cdecimal_test.py

bson/decimal128.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,12 @@ def _bit_length(num):
8484
decimal.Inexact]
8585
}
8686

87-
if _PY3:
87+
try:
88+
# Python >= 3.3, cdecimal
89+
decimal.Context(clamp=1) # pylint: disable=unexpected-keyword-arg
8890
_CTX_OPTIONS['clamp'] = 1
89-
else:
91+
except TypeError:
92+
# Python < 3.3
9093
_CTX_OPTIONS['_clamp'] = 1
9194

9295
_DEC128_CTX = decimal.Context(**_CTX_OPTIONS.copy())
@@ -273,7 +276,7 @@ def to_decimal(self):
273276
elif (high & _NAN) == _NAN:
274277
return decimal.Decimal((sign, (), 'n'))
275278
elif (high & _INF) == _INF:
276-
return decimal.Decimal((sign, (0,), 'F'))
279+
return decimal.Decimal((sign, (), 'F'))
277280

278281
if (high & _EXPONENT_MASK) == _EXPONENT_MASK:
279282
exponent = ((high & 0x1fffe00000000000) >> 47) - _EXPONENT_BIAS
@@ -296,7 +299,9 @@ def to_decimal(self):
296299
arr[0] = (high & mask) >> 48
297300

298301
# Have to convert bytearray to bytes for python 2.6.
299-
digits = [int(digit) for digit in str(_from_bytes(bytes(arr), 'big'))]
302+
# cdecimal only accepts a tuple for digits.
303+
digits = tuple(
304+
int(digit) for digit in str(_from_bytes(bytes(arr), 'big')))
300305

301306
with decimal.localcontext(_DEC128_CTX) as ctx:
302307
return ctx.create_decimal((sign, digits, exponent))

cdecimal_test.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Copyright 2017 MongoDB, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Test PyMongo with cdecimal monkey-patched over stdlib decimal."""
16+
17+
import getopt
18+
import sys
19+
20+
try:
21+
import cdecimal
22+
_HAVE_CDECIMAL = True
23+
except ImportError:
24+
_HAVE_CDECIMAL = False
25+
26+
27+
def run(args):
28+
"""Run tests with cdecimal monkey-patched over stdlib decimal."""
29+
# Monkey-patch.
30+
sys.modules['decimal'] = cdecimal
31+
32+
# Run the tests.
33+
sys.argv[:] = ['setup.py', 'test'] + list(args)
34+
import setup
35+
36+
37+
def main():
38+
"""Parse options and run tests."""
39+
usage = """python %s
40+
41+
Test PyMongo with cdecimal monkey-patched over decimal.""" % (sys.argv[0],)
42+
43+
try:
44+
opts, args = getopt.getopt(
45+
sys.argv[1:], "h", ["help"])
46+
except getopt.GetoptError as err:
47+
print(str(err))
48+
print(usage)
49+
sys.exit(2)
50+
51+
for option_name, _ in opts:
52+
if option_name in ("-h", "--help"):
53+
print(usage)
54+
sys.exit()
55+
else:
56+
assert False, "unhandled option"
57+
58+
if not _HAVE_CDECIMAL:
59+
print("The cdecimal package is not installed.")
60+
sys.exit(1)
61+
62+
run(args) # Command line args to setup.py, like what test to run.
63+
64+
65+
if __name__ == '__main__':
66+
main()

0 commit comments

Comments
 (0)