[7.x] Start testing on Python 3.10
Co-authored-by: Seth Michael Larson <[email protected]>
This commit is contained in:
co-authored by
Seth Michael Larson
parent
ce6be4cd98
commit
1787f64d02
@@ -12,6 +12,7 @@ PYTHON_VERSION:
|
|||||||
- 3.7
|
- 3.7
|
||||||
- 3.8
|
- 3.8
|
||||||
- 3.9
|
- 3.9
|
||||||
|
- 3.10
|
||||||
|
|
||||||
PYTHON_CONNECTION_CLASS:
|
PYTHON_CONNECTION_CLASS:
|
||||||
- Urllib3HttpConnection
|
- Urllib3HttpConnection
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ jobs:
|
|||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v1
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
- name: Set up Python 3.7
|
- name: Set up Python 3.7
|
||||||
uses: actions/setup-python@v1
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: 3.7
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@@ -41,7 +41,7 @@ jobs:
|
|||||||
python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9]
|
python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9]
|
||||||
experimental: [false]
|
experimental: [false]
|
||||||
include:
|
include:
|
||||||
- python-version: 3.9-dev
|
- python-version: 3.10.0-beta.2
|
||||||
experimental: true
|
experimental: true
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -51,7 +51,7 @@ jobs:
|
|||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
- name: Set Up Python - ${{ matrix.python-version }}
|
- name: Set Up Python - ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v1
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
|
|||||||
@@ -6,12 +6,15 @@ mock
|
|||||||
sphinx<1.7
|
sphinx<1.7
|
||||||
sphinx_rtd_theme
|
sphinx_rtd_theme
|
||||||
jinja2
|
jinja2
|
||||||
numpy
|
|
||||||
pandas
|
# No wheels for Python 3.10 yet!
|
||||||
|
numpy; python_version<"3.10"
|
||||||
|
pandas; python_version<"3.10"
|
||||||
|
|
||||||
# PyYAML 5.3 dropped support for Python 3.4 while
|
# PyYAML 5.3 dropped support for Python 3.4 while
|
||||||
# not amending that requirement to the package. :(
|
# not amending that requirement to the package. :(
|
||||||
pyyaml<5.3
|
pyyaml>=5.4; python_version>="3.6"
|
||||||
|
pyyaml<5.3; python_version<"3.6"
|
||||||
|
|
||||||
isort
|
isort
|
||||||
black; python_version>="3.6"
|
black; python_version>="3.6"
|
||||||
|
|||||||
@@ -167,7 +167,10 @@ class AIOHttpConnection(AsyncConnection):
|
|||||||
|
|
||||||
self.ssl_assert_fingerprint = ssl_assert_fingerprint
|
self.ssl_assert_fingerprint = ssl_assert_fingerprint
|
||||||
if self.use_ssl and ssl_context is None:
|
if self.use_ssl and ssl_context is None:
|
||||||
ssl_context = ssl.SSLContext(ssl_version or ssl.PROTOCOL_TLS)
|
if ssl_version is None:
|
||||||
|
ssl_context = ssl.create_default_context()
|
||||||
|
else:
|
||||||
|
ssl_context = ssl.SSLContext(ssl_version)
|
||||||
|
|
||||||
# Convert all sentinel values to their actual default
|
# Convert all sentinel values to their actual default
|
||||||
# values if not using an SSLContext.
|
# values if not using an SSLContext.
|
||||||
@@ -180,8 +183,8 @@ class AIOHttpConnection(AsyncConnection):
|
|||||||
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
||||||
ssl_context.check_hostname = True
|
ssl_context.check_hostname = True
|
||||||
else:
|
else:
|
||||||
ssl_context.verify_mode = ssl.CERT_NONE
|
|
||||||
ssl_context.check_hostname = False
|
ssl_context.check_hostname = False
|
||||||
|
ssl_context.verify_mode = ssl.CERT_NONE
|
||||||
|
|
||||||
ca_certs = CA_CERTS if ca_certs is None else ca_certs
|
ca_certs = CA_CERTS if ca_certs is None else ca_certs
|
||||||
if verify_certs:
|
if verify_certs:
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ class TestAIOHttpConnection:
|
|||||||
use_ssl=True, verify_certs=False, ssl_show_warn=False
|
use_ssl=True, verify_certs=False, ssl_show_warn=False
|
||||||
)
|
)
|
||||||
await con._create_aiohttp_session()
|
await con._create_aiohttp_session()
|
||||||
assert 0 == len(w)
|
assert w == []
|
||||||
|
|
||||||
assert isinstance(con.session, aiohttp.ClientSession)
|
assert isinstance(con.session, aiohttp.ClientSession)
|
||||||
|
|
||||||
@@ -277,7 +277,7 @@ class TestAIOHttpConnection:
|
|||||||
ctx = ssl.create_default_context()
|
ctx = ssl.create_default_context()
|
||||||
with warnings.catch_warnings(record=True) as w:
|
with warnings.catch_warnings(record=True) as w:
|
||||||
AIOHttpConnection(ssl_context=ctx)
|
AIOHttpConnection(ssl_context=ctx)
|
||||||
assert 0 == len(w), str([x.message for x in w])
|
assert w == [], str([x.message for x in w])
|
||||||
|
|
||||||
def test_warns_if_using_non_default_ssl_kwargs_with_ssl_context(self):
|
def test_warns_if_using_non_default_ssl_kwargs_with_ssl_context(self):
|
||||||
for kwargs in (
|
for kwargs in (
|
||||||
|
|||||||
@@ -21,8 +21,11 @@ import uuid
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
import numpy as np
|
try:
|
||||||
import pandas as pd
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
except ImportError:
|
||||||
|
np = pd = None
|
||||||
|
|
||||||
from elasticsearch.exceptions import ImproperlyConfigured, SerializationError
|
from elasticsearch.exceptions import ImproperlyConfigured, SerializationError
|
||||||
from elasticsearch.serializer import (
|
from elasticsearch.serializer import (
|
||||||
@@ -35,6 +38,11 @@ from elasticsearch.serializer import (
|
|||||||
from .test_cases import SkipTest, TestCase
|
from .test_cases import SkipTest, TestCase
|
||||||
|
|
||||||
|
|
||||||
|
def requires_numpy_and_pandas():
|
||||||
|
if np is None or pd is None:
|
||||||
|
raise SkipTest("Test requires numpy or pandas to be available")
|
||||||
|
|
||||||
|
|
||||||
class TestJSONSerializer(TestCase):
|
class TestJSONSerializer(TestCase):
|
||||||
def test_datetime_serialization(self):
|
def test_datetime_serialization(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -43,6 +51,8 @@ class TestJSONSerializer(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_decimal_serialization(self):
|
def test_decimal_serialization(self):
|
||||||
|
requires_numpy_and_pandas()
|
||||||
|
|
||||||
if sys.version_info[:2] == (2, 6):
|
if sys.version_info[:2] == (2, 6):
|
||||||
raise SkipTest("Float rounding is broken in 2.6.")
|
raise SkipTest("Float rounding is broken in 2.6.")
|
||||||
self.assertEqual('{"d":3.8}', JSONSerializer().dumps({"d": Decimal("3.8")}))
|
self.assertEqual('{"d":3.8}', JSONSerializer().dumps({"d": Decimal("3.8")}))
|
||||||
@@ -56,9 +66,13 @@ class TestJSONSerializer(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_serializes_numpy_bool(self):
|
def test_serializes_numpy_bool(self):
|
||||||
|
requires_numpy_and_pandas()
|
||||||
|
|
||||||
self.assertEqual('{"d":true}', JSONSerializer().dumps({"d": np.bool_(True)}))
|
self.assertEqual('{"d":true}', JSONSerializer().dumps({"d": np.bool_(True)}))
|
||||||
|
|
||||||
def test_serializes_numpy_integers(self):
|
def test_serializes_numpy_integers(self):
|
||||||
|
requires_numpy_and_pandas()
|
||||||
|
|
||||||
ser = JSONSerializer()
|
ser = JSONSerializer()
|
||||||
for np_type in (
|
for np_type in (
|
||||||
np.int_,
|
np.int_,
|
||||||
@@ -78,6 +92,8 @@ class TestJSONSerializer(TestCase):
|
|||||||
self.assertEqual(ser.dumps({"d": np_type(1)}), '{"d":1}')
|
self.assertEqual(ser.dumps({"d": np_type(1)}), '{"d":1}')
|
||||||
|
|
||||||
def test_serializes_numpy_floats(self):
|
def test_serializes_numpy_floats(self):
|
||||||
|
requires_numpy_and_pandas()
|
||||||
|
|
||||||
ser = JSONSerializer()
|
ser = JSONSerializer()
|
||||||
for np_type in (
|
for np_type in (
|
||||||
np.float_,
|
np.float_,
|
||||||
@@ -89,12 +105,16 @@ class TestJSONSerializer(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_serializes_numpy_datetime(self):
|
def test_serializes_numpy_datetime(self):
|
||||||
|
requires_numpy_and_pandas()
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'{"d":"2010-10-01T02:30:00"}',
|
'{"d":"2010-10-01T02:30:00"}',
|
||||||
JSONSerializer().dumps({"d": np.datetime64("2010-10-01T02:30:00")}),
|
JSONSerializer().dumps({"d": np.datetime64("2010-10-01T02:30:00")}),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_serializes_numpy_ndarray(self):
|
def test_serializes_numpy_ndarray(self):
|
||||||
|
requires_numpy_and_pandas()
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'{"d":[0,0,0,0,0]}',
|
'{"d":[0,0,0,0,0]}',
|
||||||
JSONSerializer().dumps({"d": np.zeros((5,), dtype=np.uint8)}),
|
JSONSerializer().dumps({"d": np.zeros((5,), dtype=np.uint8)}),
|
||||||
@@ -106,24 +126,32 @@ class TestJSONSerializer(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_serializes_numpy_nan_to_nan(self):
|
def test_serializes_numpy_nan_to_nan(self):
|
||||||
|
requires_numpy_and_pandas()
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'{"d":NaN}',
|
'{"d":NaN}',
|
||||||
JSONSerializer().dumps({"d": np.nan}),
|
JSONSerializer().dumps({"d": np.nan}),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_serializes_pandas_timestamp(self):
|
def test_serializes_pandas_timestamp(self):
|
||||||
|
requires_numpy_and_pandas()
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'{"d":"2010-10-01T02:30:00"}',
|
'{"d":"2010-10-01T02:30:00"}',
|
||||||
JSONSerializer().dumps({"d": pd.Timestamp("2010-10-01T02:30:00")}),
|
JSONSerializer().dumps({"d": pd.Timestamp("2010-10-01T02:30:00")}),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_serializes_pandas_series(self):
|
def test_serializes_pandas_series(self):
|
||||||
|
requires_numpy_and_pandas()
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'{"d":["a","b","c","d"]}',
|
'{"d":["a","b","c","d"]}',
|
||||||
JSONSerializer().dumps({"d": pd.Series(["a", "b", "c", "d"])}),
|
JSONSerializer().dumps({"d": pd.Series(["a", "b", "c", "d"])}),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_serializes_pandas_na(self):
|
def test_serializes_pandas_na(self):
|
||||||
|
requires_numpy_and_pandas()
|
||||||
|
|
||||||
if not hasattr(pd, "NA"): # pandas.NA added in v1
|
if not hasattr(pd, "NA"): # pandas.NA added in v1
|
||||||
raise SkipTest("pandas.NA required")
|
raise SkipTest("pandas.NA required")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -132,11 +160,15 @@ class TestJSONSerializer(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_raises_serialization_error_pandas_nat(self):
|
def test_raises_serialization_error_pandas_nat(self):
|
||||||
|
requires_numpy_and_pandas()
|
||||||
|
|
||||||
if not hasattr(pd, "NaT"):
|
if not hasattr(pd, "NaT"):
|
||||||
raise SkipTest("pandas.NaT required")
|
raise SkipTest("pandas.NaT required")
|
||||||
self.assertRaises(SerializationError, JSONSerializer().dumps, {"d": pd.NaT})
|
self.assertRaises(SerializationError, JSONSerializer().dumps, {"d": pd.NaT})
|
||||||
|
|
||||||
def test_serializes_pandas_category(self):
|
def test_serializes_pandas_category(self):
|
||||||
|
requires_numpy_and_pandas()
|
||||||
|
|
||||||
cat = pd.Categorical(["a", "c", "b", "a"], categories=["a", "b", "c"])
|
cat = pd.Categorical(["a", "c", "b", "a"], categories=["a", "b", "c"])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'{"d":["a","c","b","a"]}',
|
'{"d":["a","c","b","a"]}',
|
||||||
|
|||||||
Reference in New Issue
Block a user