Skip to content

PYTHON-3366 Support mypy 0.971 and test with latest version #1021

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 25, 2022
Merged
4 changes: 2 additions & 2 deletions .github/workflows/test-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ jobs:
cache-dependency-path: 'setup.py'
- name: Install dependencies
run: |
python -m pip install -U pip mypy==0.942
pip install -e ".[zstd, srv]"
python -m pip install -U pip mypy
pip install -e ".[zstd, srv, encryption, ocsp]"
- name: Run mypy
run: |
mypy --install-types --non-interactive bson gridfs tools pymongo
Expand Down
12 changes: 6 additions & 6 deletions bson/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@
import struct
import sys
import uuid
from codecs import utf_8_decode as _utf_8_decode # type: ignore[attr-defined]
from codecs import utf_8_encode as _utf_8_encode # type: ignore[attr-defined]
from codecs import utf_8_decode as _utf_8_decode
from codecs import utf_8_encode as _utf_8_encode
from collections import abc as _abc
from typing import (
IO,
Expand Down Expand Up @@ -621,7 +621,7 @@ def _make_c_string_check(string: Union[str, bytes]) -> bytes:
else:
if "\x00" in string:
raise InvalidDocument("BSON keys / regex patterns must not contain a NUL character")
return cast(bytes, _utf_8_encode(string)[0]) + b"\x00"
return _utf_8_encode(string)[0] + b"\x00"


def _make_c_string(string: Union[str, bytes]) -> bytes:
Expand All @@ -633,15 +633,15 @@ def _make_c_string(string: Union[str, bytes]) -> bytes:
except UnicodeError:
raise InvalidStringData("strings in documents must be valid UTF-8: %r" % string)
else:
return cast(bytes, _utf_8_encode(string)[0]) + b"\x00"
return _utf_8_encode(string)[0] + b"\x00"


def _make_name(string: str) -> bytes:
"""Make a 'C' string suitable for a BSON key."""
# Keys can only be text in python 3.
if "\x00" in string:
raise InvalidDocument("BSON keys / regex patterns must not contain a NUL character")
return cast(bytes, _utf_8_encode(string)[0]) + b"\x00"
return _utf_8_encode(string)[0] + b"\x00"


def _encode_float(name: bytes, value: float, dummy0: Any, dummy1: Any) -> bytes:
Expand Down Expand Up @@ -1308,7 +1308,7 @@ def encode(
"""
return cls(encode(document, check_keys, codec_options))

def decode(self, codec_options: CodecOptions = DEFAULT_CODEC_OPTIONS) -> _DocumentType: # type: ignore[override]
def decode(self, codec_options: "CodecOptions[_DocumentType]" = DEFAULT_CODEC_OPTIONS) -> _DocumentType: # type: ignore[override,assignment]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "assignment" ignore is required to silence this error:

bson/__init__.py: note: In member "decode" of class "BSON":
bson/__init__.py:1311: error: Incompatible default for argument "codec_options" (default has type "CodecOptions[MutableMapping[str, Any]]", argument
has type "CodecOptions[_DocumentType]")  [assignment]
        def decode(self, codec_options: "CodecOptions[_DocumentType]" = DEFAULT_CODEC_OPTIONS) -> _DocumentType:  # type: ignore[override]

"""Decode this BSON data.

By default, returns a BSON document represented as a Python
Expand Down
2 changes: 1 addition & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,6 @@


intersphinx_mapping = {
"gevent": ("http://www.gevent.org/", None),
"gevent": ("https://www.gevent.org/", None),
"py": ("https://docs.python.org/3/", None),
}
9 changes: 3 additions & 6 deletions pymongo/pyopenssl_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def recv(self, *args, **kwargs):

def recv_into(self, *args, **kwargs):
try:
return self._call(super(_sslConn, self).recv_into, *args, **kwargs) # type: ignore
return self._call(super(_sslConn, self).recv_into, *args, **kwargs)
except _SSL.SysCallError as exc:
# Suppress ragged EOFs to match the stdlib.
if self.suppress_ragged_eofs and _ragged_eof(exc):
Expand All @@ -146,12 +146,9 @@ def sendall(self, buf, flags=0):
view = memoryview(buf)
total_length = len(buf)
total_sent = 0
sent = 0
while total_sent < total_length:
try:
sent = self._call(
super(_sslConn, self).send, view[total_sent:], flags # type: ignore
)
sent = self._call(super(_sslConn, self).send, view[total_sent:], flags)
# XXX: It's not clear if this can actually happen. PyOpenSSL
# doesn't appear to have any interrupt handling, nor any interrupt
# errors for OpenSSL connections.
Expand All @@ -162,7 +159,7 @@ def sendall(self, buf, flags=0):
# https://github.com/pyca/pyopenssl/blob/19.1.0/src/OpenSSL/SSL.py#L1756
# https://www.openssl.org/docs/man1.0.2/man3/SSL_write.html
if sent <= 0:
raise Exception("Connection closed")
raise OSError("connection closed")
total_sent += sent


Expand Down
4 changes: 2 additions & 2 deletions test/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,8 @@ def auth_string(user, password):
bad_user = MongoClient(auth_string("not-user", SASL_PASS))
bad_pwd = MongoClient(auth_string(SASL_USER, "not-pwd"))
# OperationFailure raised upon connecting.
self.assertRaises(OperationFailure, bad_user.admin.command, "ping")
self.assertRaises(OperationFailure, bad_pwd.admin.command, "ping")
self.assertRaises(OperationFailure, bad_user.admin.command, "ping") # type: ignore[arg-type]
self.assertRaises(OperationFailure, bad_pwd.admin.command, "ping") # type: ignore[arg-type]


class TestSCRAMSHA1(IntegrationTest):
Expand Down
21 changes: 16 additions & 5 deletions test/test_bson.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ def tzname(self, dt):

class TestBSON(unittest.TestCase):
def assertInvalid(self, data):
self.assertRaises(InvalidBSON, decode, data)
# Remove type ignore after: https://github.com/python/mypy/issues/13220
self.assertRaises(InvalidBSON, decode, data) # type: ignore[arg-type]

def check_encode_then_decode(self, doc_class=dict, decoder=decode, encoder=encode):

Expand Down Expand Up @@ -1025,11 +1026,17 @@ def test_unicode_decode_error_handler(self):

# Ensure that strict mode raises an error.
for invalid in [invalid_key, invalid_val, invalid_both]:
# Remove type ignore after: https://github.com/python/mypy/issues/13220
self.assertRaises(
InvalidBSON, decode, invalid, CodecOptions(unicode_decode_error_handler="strict")
InvalidBSON,
decode, # type: ignore[arg-type]
invalid,
CodecOptions(unicode_decode_error_handler="strict"),
)
self.assertRaises(InvalidBSON, decode, invalid, CodecOptions())
self.assertRaises(InvalidBSON, decode, invalid)
self.assertRaises(
InvalidBSON, decode, invalid, CodecOptions() # type: ignore[arg-type]
)
self.assertRaises(InvalidBSON, decode, invalid) # type: ignore[arg-type]

# Test all other error handlers.
for handler in ["replace", "backslashreplace", "surrogateescape", "ignore"]:
Expand All @@ -1046,8 +1053,12 @@ def test_unicode_decode_error_handler(self):
dec = decode(enc, CodecOptions(unicode_decode_error_handler="junk"))
self.assertEqual(dec, {"keystr": "foobar"})

# Remove type ignore after: https://github.com/python/mypy/issues/13220
self.assertRaises(
InvalidBSON, decode, invalid_both, CodecOptions(unicode_decode_error_handler="junk")
InvalidBSON,
decode, # type: ignore[arg-type]
invalid_both,
CodecOptions(unicode_decode_error_handler="junk"),
)

def round_trip_pickle(self, obj, pickled_with_older):
Expand Down
3 changes: 2 additions & 1 deletion test/test_change_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -1084,8 +1084,9 @@ def setFailPoint(self, scenario_dict):
fail_cmd = SON([("configureFailPoint", "failCommand")])
fail_cmd.update(fail_point)
client_context.client.admin.command(fail_cmd)
# Remove type ignore after: https://github.com/python/mypy/issues/13220
self.addCleanup(
client_context.client.admin.command,
client_context.client.admin.command, # type: ignore[arg-type]
"configureFailPoint",
fail_cmd["configureFailPoint"],
mode="off",
Expand Down
2 changes: 1 addition & 1 deletion test/test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import contextlib
import re
import sys
from codecs import utf_8_decode # type: ignore
from codecs import utf_8_decode
from collections import defaultdict
from typing import Iterable, no_type_check

Expand Down
5 changes: 3 additions & 2 deletions test/test_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -604,13 +604,14 @@ def test_command_max_time_ms(self):
try:
db = self.client.pymongo_test
db.command("count", "test")
self.assertRaises(ExecutionTimeout, db.command, "count", "test", maxTimeMS=1)
# Remove type ignore after: https://github.com/python/mypy/issues/13220
self.assertRaises(ExecutionTimeout, db.command, "count", "test", maxTimeMS=1) # type: ignore[arg-type]
pipeline = [{"$project": {"name": 1, "count": 1}}]
# Database command helper.
db.command("aggregate", "test", pipeline=pipeline, cursor={})
self.assertRaises(
ExecutionTimeout,
db.command,
db.command, # type: ignore[arg-type]
"aggregate",
"test",
pipeline=pipeline,
Expand Down