Skip to content

Commit a314632

Browse files
authored
ARROW-255 Update test config and address test failures (#240)
* get test suite running * undo docs changes * address warning * fix utc now handling * fix utc now handling * bump to 3.9+ * update changelog * lint * lint * lint * fix test
1 parent 888b803 commit a314632

File tree

13 files changed

+62
-43
lines changed

13 files changed

+62
-43
lines changed

.github/workflows/release-python.yml

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,11 @@ jobs:
3232
- [ubuntu-20.04, manylinux_aarch64]
3333
- [macos-14, macosx_*]
3434
- [windows-2019, win_amd64]
35-
python: ["cp38", "cp39", "cp310", "cp311", "cp312"]
35+
python: ["cp39", "cp310", "cp311", "cp312"]
3636
exclude:
37-
- buildplat: [macos-14, macosx_*]
38-
python: "cp38"
3937
- buildplat: [macos-14, macosx_*]
4038
python: "cp39"
4139
include:
42-
- buildplat: [macos-12, macosx_*]
43-
python: "cp38"
4440
- buildplat: [macos-12, macosx_*]
4541
python: "cp39"
4642

@@ -75,13 +71,6 @@ jobs:
7571
- name: Install cibuildwheel
7672
run: python -m pip install "cibuildwheel>=2.4,<3"
7773

78-
- name: Build MacOS Py38 Wheel
79-
if: ${{ matrix.python == 'cp38' && matrix.buildplat[0] == 'macos-11' }}
80-
env:
81-
CIBW_BUILD: cp38-macosx_x86_64
82-
MACOSX_DEPLOYMENT_TARGET: "10.14"
83-
run: python -m cibuildwheel --output-dir wheelhouse
84-
8574
- name: Build MacOS Py39 Wheels
8675
if: ${{ matrix.python == 'cp39' && matrix.buildplat[0] == 'macos-11' }}
8776
env:
@@ -114,7 +103,7 @@ jobs:
114103
- uses: actions/setup-python@v5
115104
with:
116105
# Build sdist on lowest supported Python
117-
python-version: '3.8'
106+
python-version: '3.9'
118107

119108
- name: Install tox
120109
run: |

.github/workflows/test-python.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
strategy:
3434
matrix:
3535
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
36-
python-version: [3.8, 3.9, "3.10", "3.11", "3.12"]
36+
python-version: ["3.9", "3.10", "3.11", "3.12"]
3737
fail-fast: false
3838
name: CPython ${{ matrix.python-version }}-${{ matrix.os }}
3939
steps:

bindings/python/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
---
55

6+
# Changes in Version 1.6.0
7+
8+
- Drop support for Python 3.8.
9+
610
# Changes in Version 1.5.2
711

812
- Fix support for PyMongo 4.9.

bindings/python/CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ be of interest or that has already been addressed.
1313

1414
## Supported Interpreters
1515

16-
PyMongoArrow supports CPython 3.7+ and PyPy3.8+. Language features not
16+
PyMongoArrow supports CPython 3.9+ and PyPy3.9+. Language features not
1717
supported by all interpreters can not be used.
1818

1919
## Style Guide

bindings/python/pymongoarrow/pandas_types.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
# limitations under the License.
1414

1515
# Pandas Extension Types
16+
from __future__ import annotations
1617

1718
import numbers
1819
import re
19-
from typing import Type, Union
2020

2121
import numpy as np
2222
import pandas as pd
@@ -38,7 +38,7 @@ class PandasBSONDtype(ExtensionDtype):
3838
def name(self) -> str:
3939
return f"bson_{self.__class__.__name__}"
4040

41-
def __from_arrow__(self, array: Union[pa.Array, pa.ChunkedArray]) -> ExtensionArray:
41+
def __from_arrow__(self, array: pa.Array | pa.ChunkedArray) -> ExtensionArray:
4242
chunks = [array] if isinstance(array, pa.Array) else array.chunks
4343

4444
arr_type = self.construct_array_type()
@@ -204,7 +204,7 @@ def name(self) -> str:
204204
return f"bson_{self.type.__name__}[{self.subtype}]"
205205

206206
@classmethod
207-
def construct_array_type(cls) -> Type["PandasBinaryArray"]:
207+
def construct_array_type(cls) -> type[PandasBinaryArray]:
208208
return PandasBinaryArray
209209

210210
@classmethod
@@ -242,7 +242,7 @@ class PandasObjectId(PandasBSONDtype):
242242
type = ObjectId
243243

244244
@classmethod
245-
def construct_array_type(cls) -> Type["PandasObjectIdArray"]:
245+
def construct_array_type(cls) -> type[PandasObjectIdArray]:
246246
return PandasObjectIdArray
247247

248248

@@ -266,7 +266,7 @@ class PandasDecimal128(PandasBSONDtype):
266266
type = Decimal128
267267

268268
@classmethod
269-
def construct_array_type(cls) -> Type["PandasDecimal128Array"]:
269+
def construct_array_type(cls) -> type[PandasDecimal128Array]:
270270
return PandasDecimal128Array
271271

272272

@@ -290,7 +290,7 @@ class PandasCode(PandasBSONDtype):
290290
type = Code
291291

292292
@classmethod
293-
def construct_array_type(cls) -> Type["PandasCodeArray"]:
293+
def construct_array_type(cls) -> type[PandasCodeArray]:
294294
return PandasCodeArray
295295

296296

bindings/python/pyproject.toml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ classifiers = [
2323
"Operating System :: POSIX",
2424
"Programming Language :: Python :: 3",
2525
"Programming Language :: Python :: 3 :: Only",
26-
"Programming Language :: Python :: 3.8",
2726
"Programming Language :: Python :: 3.9",
2827
"Programming Language :: Python :: 3.10",
2928
"Programming Language :: Python :: 3.11",
@@ -32,7 +31,7 @@ classifiers = [
3231
"Topic :: Database",
3332
]
3433
readme = "README.md"
35-
requires-python = ">=3.8"
34+
requires-python = ">=3.9"
3635
dependencies = [
3736
# Must be kept in sync with "build_sytem.requires" above.
3837
"pyarrow >=17.0,<17.1",
@@ -95,9 +94,8 @@ archs = "x86_64 arm64"
9594
[tool.pytest.ini_options]
9695
minversion = "7"
9796
addopts = ["-ra", "--strict-config", "--strict-markers", "--durations=5", "--junitxml=xunit-results/TEST-results.xml"]
98-
testpaths = ["test", "test/pandas_types"]
97+
testpaths = ["test"]
9998
log_cli_level = "INFO"
100-
norecursedirs = ["test/*"]
10199
faulthandler_timeout = 1500
102100
xfail_strict = true
103101
filterwarnings = [

bindings/python/test/test_arrow.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ def setUpClass(cls):
7474
cls.coll = cls.client.pymongoarrow_test.get_collection(
7575
"test", write_concern=WriteConcern(w="majority")
7676
)
77+
cls.addClassCleanup(cls.client.close)
7778

7879
def setUp(self):
7980
self.coll.drop()
@@ -113,6 +114,14 @@ def test_find_simple(self):
113114
self.assertEqual(find_cmd.command_name, "find")
114115
self.assertEqual(find_cmd.command["projection"], {"_id": True, "data": True})
115116

117+
def test_find_repeat_type(self):
118+
expected = Table.from_pydict(
119+
{"_id": [1, 2, 3, 4], "data": [10, 20, 30, None]},
120+
ArrowSchema([("_id", int32()), ("data", int32())]),
121+
)
122+
table = self.run_find({}, schema=Schema({"_id": int32(), "data": int32()}))
123+
self.assertEqual(table, expected)
124+
116125
def test_find_with_projection(self):
117126
expected = Table.from_pydict(
118127
{"_id": [4, 3], "data": [None, 60]},
@@ -266,18 +275,19 @@ def test_pymongo_error(self):
266275
},
267276
ArrowSchema(schema),
268277
)
269-
278+
client = MongoClient(
279+
host="somedomainthatdoesntexist.org",
280+
port=123456789,
281+
serverSelectionTimeoutMS=10,
282+
)
270283
with self.assertRaises(ArrowWriteError) as exc:
271284
write(
272-
MongoClient(
273-
host="somedomainthatdoesntexist.org",
274-
port=123456789,
275-
serverSelectionTimeoutMS=10,
276-
).pymongoarrow_test.get_collection(
285+
client.pymongoarrow_test.get_collection(
277286
"test", write_concern=WriteConcern(w="majority")
278287
),
279288
data,
280289
)
290+
client.close()
281291
self.assertEqual(
282292
exc.exception.details.keys(),
283293
{"nInserted", "writeConcernErrors", "writeErrors"},
@@ -840,6 +850,7 @@ def setUpClass(cls):
840850
cls.client = client_context.get_client(
841851
event_listeners=[cls.getmore_listener, cls.cmd_listener]
842852
)
853+
cls.addClassCleanup(cls.client.close)
843854

844855
def test_find_decimal128(self):
845856
oids = list(ObjectId() for i in range(4))

bindings/python/test/test_builders.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
import calendar
15-
from datetime import date, datetime, timedelta
15+
from datetime import date, datetime, timedelta, timezone
1616
from unittest import TestCase
1717

1818
from bson import Binary, Code, Decimal128, ObjectId
@@ -86,7 +86,7 @@ def test_simple(self):
8686
self.maxDiff = None
8787

8888
builder = DatetimeBuilder(dtype=timestamp("ms"))
89-
datetimes = [datetime.utcnow() + timedelta(days=k * 100) for k in range(5)]
89+
datetimes = [datetime.now(timezone.utc) + timedelta(days=k * 100) for k in range(5)]
9090
builder.append(self._datetime_to_millis(datetimes[0]))
9191
builder.append_values([self._datetime_to_millis(k) for k in datetimes[1:]])
9292
builder.append_null()
@@ -97,7 +97,9 @@ def test_simple(self):
9797
self.assertEqual(len(arr), len(datetimes) + 1)
9898
for actual, expected in zip(arr, datetimes + [None]):
9999
if actual.is_valid:
100-
self.assertEqual(actual.as_py(), self._millis_only(expected))
100+
self.assertEqual(
101+
actual.as_py().timetuple(), self._millis_only(expected).timetuple()
102+
)
101103
else:
102104
self.assertIsNone(expected)
103105
self.assertEqual(arr.type, timestamp("ms"))

bindings/python/test/test_datetime.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
import unittest
15-
from datetime import datetime, timedelta
15+
from datetime import datetime, timedelta, timezone
1616
from test import client_context
1717

1818
import pytz
@@ -36,14 +36,17 @@ def setUp(self):
3636
self.coll.drop()
3737
self.coll.insert_many(
3838
[
39-
{"_id": 1, "data": datetime.utcnow() + timedelta(milliseconds=10)},
40-
{"_id": 2, "data": datetime.utcnow() + timedelta(milliseconds=25)},
39+
{"_id": 1, "data": datetime.now(timezone.utc) + timedelta(milliseconds=10)},
40+
{"_id": 2, "data": datetime.now(timezone.utc) + timedelta(milliseconds=25)},
4141
]
4242
)
4343
self.expected_times = []
4444
for doc in self.coll.find({}, sort=[("_id", ASCENDING)]):
4545
self.expected_times.append(doc["data"])
4646

47+
def tearDown(self):
48+
self.client.close()
49+
4750
def test_context_creation_fails_with_unsupported_granularity(self):
4851
unsupported_granularities = ["s", "us", "ns"]
4952
for g in unsupported_granularities:

bindings/python/test/test_numpy.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ def setUpClass(cls):
4242
)
4343
cls.schema = {}
4444

45+
@classmethod
46+
def tearDownClass(cls):
47+
cls.client.close()
48+
4549
def assert_numpy_equal(self, actual, expected):
4650
self.assertIsInstance(actual, dict)
4751
for field in expected:
@@ -321,7 +325,7 @@ def table_from_dict(self, d, schema=None):
321325
out = {}
322326
for k, v in d.items():
323327
if any(isinstance(x, int) for x in v) and None in v:
324-
out[k] = np.array(v, dtype=np.float_)
328+
out[k] = np.array(v, dtype=np.float64)
325329
else:
326330
out[k] = np.array(v, dtype=np.dtype(type(v[0]))) # Infer
327331
return out

0 commit comments

Comments
 (0)