IMAPClient 4.0.1__tar.gz → 4.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. {imapclient-4.0.1 → imapclient-4.1.0}/AUTHORS.rst +1 -1
  2. {imapclient-4.0.1 → imapclient-4.1.0/IMAPClient.egg-info}/PKG-INFO +1 -1
  3. {imapclient-4.0.1 → imapclient-4.1.0}/IMAPClient.egg-info/SOURCES.txt +2 -0
  4. {imapclient-4.0.1/IMAPClient.egg-info → imapclient-4.1.0}/PKG-INFO +1 -1
  5. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/imapclient.py +8 -4
  6. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/tls.py +9 -3
  7. {imapclient-4.0.1 → imapclient-4.1.0}/pyproject.toml +1 -1
  8. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_starttls.py +15 -18
  9. imapclient-4.1.0/tests/test_starttls_integration.py +162 -0
  10. imapclient-4.1.0/tests/test_tls_integration.py +133 -0
  11. {imapclient-4.0.1 → imapclient-4.1.0}/COPYING +0 -0
  12. {imapclient-4.0.1 → imapclient-4.1.0}/IMAPClient.egg-info/dependency_links.txt +0 -0
  13. {imapclient-4.0.1 → imapclient-4.1.0}/IMAPClient.egg-info/entry_points.txt +0 -0
  14. {imapclient-4.0.1 → imapclient-4.1.0}/IMAPClient.egg-info/top_level.txt +0 -0
  15. {imapclient-4.0.1 → imapclient-4.1.0}/README.rst +0 -0
  16. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/__init__.py +0 -0
  17. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/config.py +0 -0
  18. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/datetime_util.py +0 -0
  19. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/exceptions.py +0 -0
  20. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/fixed_offset.py +0 -0
  21. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/imap4.py +0 -0
  22. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/imap_utf7.py +0 -0
  23. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/interact.py +0 -0
  24. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/livetest.py +0 -0
  25. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/response_lexer.py +0 -0
  26. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/response_parser.py +0 -0
  27. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/response_types.py +0 -0
  28. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/testable_imapclient.py +0 -0
  29. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/typing_imapclient.py +0 -0
  30. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/util.py +0 -0
  31. {imapclient-4.0.1 → imapclient-4.1.0}/imapclient/version.py +0 -0
  32. {imapclient-4.0.1 → imapclient-4.1.0}/setup.cfg +0 -0
  33. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_auth.py +0 -0
  34. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_datetime_util.py +0 -0
  35. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_enable.py +0 -0
  36. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_fixed_offset.py +0 -0
  37. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_folder_status.py +0 -0
  38. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_imap_utf7.py +0 -0
  39. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_imapclient.py +0 -0
  40. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_init.py +0 -0
  41. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_response_lexer.py +0 -0
  42. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_response_parser.py +0 -0
  43. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_search.py +0 -0
  44. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_sort.py +0 -0
  45. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_store.py +0 -0
  46. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_thread.py +0 -0
  47. {imapclient-4.0.1 → imapclient-4.1.0}/tests/test_util_functions.py +0 -0
@@ -48,4 +48,4 @@ project:
48
48
  - Sean Whalen
49
49
  - Peter Wienemann
50
50
  - Arnout Engelen
51
-
51
+ - Lars Artmann
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: IMAPClient
3
- Version: 4.0.1
3
+ Version: 4.1.0
4
4
  Summary: Easy-to-use, Pythonic and complete IMAP client library
5
5
  Author-email: Menno Finlay-Smits <hello@menno.io>
6
6
  Maintainer-email: IMAPClient Maintainers <imapclient@groups.io>
@@ -38,6 +38,8 @@ tests/test_response_parser.py
38
38
  tests/test_search.py
39
39
  tests/test_sort.py
40
40
  tests/test_starttls.py
41
+ tests/test_starttls_integration.py
41
42
  tests/test_store.py
42
43
  tests/test_thread.py
44
+ tests/test_tls_integration.py
43
45
  tests/test_util_functions.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: IMAPClient
3
- Version: 4.0.1
3
+ Version: 4.1.0
4
4
  Summary: Easy-to-use, Pythonic and complete IMAP client library
5
5
  Author-email: Menno Finlay-Smits <hello@menno.io>
6
6
  Maintainer-email: IMAPClient Maintainers <imapclient@groups.io>
@@ -378,13 +378,17 @@ class IMAPClient:
378
378
  if self.ssl or self._starttls_done:
379
379
  raise exceptions.IMAPClientAbortError("TLS session already established")
380
380
 
381
- typ, data = self._imap._simple_command("STARTTLS")
381
+ # Delegate the socket wrap to imaplib: it manages its own read buffer
382
+ # since Python 3.14 (where IMAP4.file became a read-only property).
383
+ # imaplib's own None-fallback context does not verify certificates, so
384
+ # pass IMAPClient's verifying default instead.
385
+ if ssl_context is None:
386
+ ssl_context = tls.create_default_context()
387
+
388
+ typ, data = self._imap.starttls(ssl_context=ssl_context)
382
389
  self._checkok("starttls", typ, data)
383
390
 
384
391
  self._starttls_done = True
385
-
386
- self._imap.sock = tls.wrap_socket(self._imap.sock, ssl_context, self.host)
387
- self._imap.file = self._imap.sock.makefile("rb")
388
392
  return data[0]
389
393
 
390
394
  def login(self, username: str, password: str):
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023, Menno Smits
1
+ # Copyright (c) 2026, Menno Smits
2
2
  # Released subject to the New BSD License
3
3
  # Please see http://en.wikipedia.org/wiki/BSD_licenses
4
4
 
@@ -13,11 +13,15 @@ import ssl
13
13
  from typing import Optional
14
14
 
15
15
 
16
+ def create_default_context() -> ssl.SSLContext:
17
+ return ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)
18
+
19
+
16
20
  def wrap_socket(
17
21
  sock: socket.socket, ssl_context: Optional[ssl.SSLContext], host: str
18
22
  ) -> socket.socket:
19
23
  if ssl_context is None:
20
- ssl_context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)
24
+ ssl_context = create_default_context()
21
25
 
22
26
  return ssl_context.wrap_socket(sock, server_hostname=host)
23
27
 
@@ -39,7 +43,9 @@ class IMAP4_TLS(imaplib.IMAP4):
39
43
  self._timeout = timeout
40
44
  super().__init__(host, port)
41
45
 
42
- def _create_socket(self, timeout: Optional[float]) -> socket.socket:
46
+ def _create_socket(self, timeout: Optional[float] = None) -> socket.socket:
47
+ if timeout is None:
48
+ timeout = self._timeout
43
49
  sock = socket.create_connection((self.host, self.port), timeout=timeout)
44
50
 
45
51
  return wrap_socket(sock, self.ssl_context, self.host)
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "IMAPClient"
3
3
  description = "Easy-to-use, Pythonic and complete IMAP client library"
4
- version = "4.0.1"
4
+ version = "4.1.0"
5
5
  authors = [
6
6
  {name = "Menno Finlay-Smits", email = "hello@menno.io"},
7
7
  ]
@@ -2,7 +2,7 @@
2
2
  # Released subject to the New BSD License
3
3
  # Please see http://en.wikipedia.org/wiki/BSD_licenses
4
4
 
5
- from unittest.mock import Mock, patch, sentinel
5
+ from unittest.mock import patch, sentinel
6
6
 
7
7
  from imapclient.exceptions import IMAPClientError
8
8
  from imapclient.imapclient import IMAPClient
@@ -18,34 +18,31 @@ class TestStarttls(IMAPClientTest):
18
18
  self.tls = patcher.start()
19
19
  self.addCleanup(patcher.stop)
20
20
 
21
- self.client._imap.sock = sentinel.old_sock
22
-
23
- self.new_sock = Mock()
24
- self.new_sock.makefile.return_value = sentinel.file
25
- self.tls.wrap_socket.return_value = self.new_sock
26
-
27
- self.client.host = sentinel.host
28
21
  self.client.ssl = False
29
22
  self.client._starttls_done = False
30
- self.client._imap._simple_command.return_value = "OK", [
31
- b"start TLS negotiation"
32
- ]
23
+ self.client._imap.starttls.return_value = "OK", [b"start TLS negotiation"]
33
24
  self.client._cached_capabilities = [b"STARTTLS"]
34
25
 
35
26
  def test_works(self):
36
27
  resp = self.client.starttls(sentinel.ssl_context)
37
28
 
38
- self.tls.wrap_socket.assert_called_once_with(
39
- sentinel.old_sock,
40
- sentinel.ssl_context,
41
- sentinel.host,
29
+ self.client._imap.starttls.assert_called_once_with(
30
+ ssl_context=sentinel.ssl_context
31
+ )
32
+ self.tls.create_default_context.assert_not_called()
33
+ self.assertTrue(self.client._starttls_done)
34
+ self.assertEqual(resp, b"start TLS negotiation")
35
+
36
+ def test_default_context_is_used(self):
37
+ resp = self.client.starttls()
38
+
39
+ self.client._imap.starttls.assert_called_once_with(
40
+ ssl_context=self.tls.create_default_context.return_value
42
41
  )
43
- self.new_sock.makefile.assert_called_once_with("rb")
44
- self.assertEqual(self.client._imap.file, sentinel.file)
45
42
  self.assertEqual(resp, b"start TLS negotiation")
46
43
 
47
44
  def test_command_fails(self):
48
- self.client._imap._simple_command.return_value = "NO", [b"sorry"]
45
+ self.client._imap.starttls.return_value = "NO", [b"sorry"]
49
46
 
50
47
  with self.assertRaises(IMAPClientError) as raised:
51
48
  self.client.starttls(sentinel.ssl_context)
@@ -0,0 +1,162 @@
1
+ # Copyright (c) 2025, Menno Smits
2
+ # Released subject to the New BSD License
3
+ # Please see http://en.wikipedia.org/wiki/BSD_licenses
4
+
5
+ """Integration tests for starttls() over a real socket pair.
6
+
7
+ These exercise the actual imaplib starttls code path (socket wrap plus
8
+ read-buffer refresh), which unit tests with mocked IMAP4 objects cannot
9
+ cover. This is the path that broke on Python 3.14, where IMAP4.file
10
+ became a read-only property.
11
+ """
12
+
13
+ import os
14
+ import socket
15
+ import ssl
16
+ import sys
17
+ import threading
18
+ import unittest
19
+ from pathlib import Path
20
+
21
+ from imapclient.exceptions import IMAPClientError
22
+ from imapclient.imapclient import IMAPClient
23
+
24
+ CERT_DIR = Path(__file__).parent / "certs"
25
+ CA_FILE = CERT_DIR / "ca.pem"
26
+ SERVER_CERT = CERT_DIR / "server.pem"
27
+ SERVER_KEY = CERT_DIR / "server.key"
28
+
29
+ PRE_TLS_CAPS = b"IMAP4rev1 STARTTLS AUTH=PLAIN"
30
+ POST_TLS_CAPS = b"IMAP4rev1 AUTH=PLAIN"
31
+
32
+
33
+ class FakeSTARTTLSServer:
34
+ """Minimal IMAP4 server that upgrades to TLS when told STARTTLS.
35
+
36
+ Serves one connection per instance. Post-TLS CAPABILITY responses omit
37
+ STARTTLS, mirroring what real servers advertise once the connection is
38
+ secured.
39
+ """
40
+
41
+ def __init__(self):
42
+ self.refuse_tls = False
43
+ self.error = None
44
+ self.ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
45
+ self.ctx.load_cert_chain(str(SERVER_CERT), str(SERVER_KEY))
46
+ self.sock = socket.socket()
47
+ self.sock.bind(("127.0.0.1", 0))
48
+ self.sock.listen(1)
49
+ self.port = self.sock.getsockname()[1]
50
+ self.thread = threading.Thread(target=self._serve, daemon=True)
51
+ self.thread.start()
52
+
53
+ def _reply_caps(self, conn, tag, caps):
54
+ conn.sendall(b"* CAPABILITY " + caps + b"\r\n")
55
+ conn.sendall(tag + b" OK CAPABILITY completed\r\n")
56
+
57
+ def _serve(self):
58
+ try:
59
+ conn, _ = self.sock.accept()
60
+ conn.sendall(
61
+ b"* OK [CAPABILITY " + PRE_TLS_CAPS + b"] fake server ready\r\n"
62
+ )
63
+ f = conn.makefile("rb")
64
+ while True:
65
+ line = f.readline()
66
+ if not line:
67
+ break
68
+ parts = line.split(None, 1)
69
+ tag = parts[0]
70
+ cmd = parts[1].strip().upper() if len(parts) > 1 else b""
71
+ if cmd.startswith(b"CAPABILITY"):
72
+ self._reply_caps(conn, tag, PRE_TLS_CAPS)
73
+ elif cmd.startswith(b"STARTTLS"):
74
+ if self.refuse_tls:
75
+ conn.sendall(tag + b" NO TLS refused\r\n")
76
+ continue
77
+ conn.sendall(tag + b" OK Begin TLS now\r\n")
78
+ self._serve_tls(self.ctx.wrap_socket(conn, server_side=True))
79
+ return
80
+ elif cmd.startswith(b"LOGOUT"):
81
+ conn.sendall(b"* BYE fake server signing off\r\n")
82
+ conn.sendall(tag + b" OK LOGOUT completed\r\n")
83
+ conn.close()
84
+ return
85
+ else:
86
+ conn.sendall(tag + b" OK done\r\n")
87
+ except Exception as e:
88
+ self.error = e
89
+
90
+ def _serve_tls(self, conn):
91
+ f = conn.makefile("rb")
92
+ while True:
93
+ line = f.readline()
94
+ if not line:
95
+ break
96
+ parts = line.split(None, 1)
97
+ tag = parts[0]
98
+ cmd = parts[1].strip().upper() if len(parts) > 1 else b""
99
+ if cmd.startswith(b"CAPABILITY"):
100
+ self._reply_caps(conn, tag, POST_TLS_CAPS)
101
+ elif cmd.startswith(b"LOGOUT"):
102
+ conn.sendall(b"* BYE fake server signing off\r\n")
103
+ conn.sendall(tag + b" OK LOGOUT completed\r\n")
104
+ conn.close()
105
+ return
106
+ else:
107
+ conn.sendall(tag + b" OK done\r\n")
108
+
109
+
110
+ @unittest.skipIf(
111
+ sys.version_info < (3, 9),
112
+ "imaplib.IMAP4 gained the timeout parameter in Python 3.9",
113
+ )
114
+ class StarttlsSocketTests(unittest.TestCase):
115
+ def setUp(self):
116
+ self.server = FakeSTARTTLSServer()
117
+ self._saved_cert_file = os.environ.pop("SSL_CERT_FILE", None)
118
+ os.environ["SSL_CERT_FILE"] = str(CA_FILE)
119
+
120
+ def tearDown(self):
121
+ if self._saved_cert_file is not None:
122
+ os.environ["SSL_CERT_FILE"] = self._saved_cert_file
123
+ self.server.sock.close()
124
+ self.assertIsNone(self.server.error)
125
+
126
+ def _client(self):
127
+ return IMAPClient("localhost", self.server.port, ssl=False)
128
+
129
+ def test_starttls_with_default_context(self):
130
+ client = self._client()
131
+
132
+ client.starttls()
133
+
134
+ sock = client._imap.sock
135
+ self.assertIsInstance(sock, ssl.SSLSocket)
136
+ # IMAPClient's documented default: hostname checking and certificate
137
+ # verification ON. imaplib's own None-fallback is unverified.
138
+ self.assertTrue(sock.context.check_hostname)
139
+ self.assertEqual(sock.context.verify_mode, ssl.CERT_REQUIRED)
140
+
141
+ self.assertNotIn(b"STARTTLS", client.capabilities())
142
+ client.login("user", "pass")
143
+ client.logout()
144
+
145
+ def test_starttls_with_custom_context(self):
146
+ context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
147
+ context.check_hostname = False
148
+ context.verify_mode = ssl.CERT_NONE
149
+
150
+ client = self._client()
151
+ client.starttls(context)
152
+
153
+ self.assertIs(client._imap.sock.context, context)
154
+ client.login("user", "pass")
155
+ client.logout()
156
+
157
+ def test_starttls_refused_raises_imapclient_error(self):
158
+ self.server.refuse_tls = True
159
+ client = self._client()
160
+
161
+ with self.assertRaises(IMAPClientError):
162
+ client.starttls()
@@ -0,0 +1,133 @@
1
+ # Copyright (c) 2025, Menno Smits
2
+ # Released subject to the New BSD License
3
+ # Please see http://en.wikipedia.org/wiki/BSD_licenses
4
+
5
+ """Integration tests for IMAPClient(..., ssl=True) over a real socket pair.
6
+
7
+ These exercise the actual TLS-from-connect code path (tls.IMAP4_TLS socket
8
+ wrap), which unit tests with mocked IMAP4 objects cannot cover. They mirror
9
+ tests/test_starttls_integration.py, but with TLS established at connection
10
+ time instead of via the STARTTLS command.
11
+ """
12
+
13
+ import os
14
+ import socket
15
+ import ssl
16
+ import sys
17
+ import threading
18
+ import unittest
19
+ from pathlib import Path
20
+
21
+ from imapclient.imapclient import IMAPClient
22
+
23
+ CERT_DIR = Path(__file__).parent / "certs"
24
+ CA_FILE = CERT_DIR / "ca.pem"
25
+ SERVER_CERT = CERT_DIR / "server.pem"
26
+ SERVER_KEY = CERT_DIR / "server.key"
27
+
28
+ CAPS = b"IMAP4rev1 AUTH=PLAIN"
29
+
30
+
31
+ class FakeTLSServer:
32
+ """Minimal IMAP4 server that speaks TLS from the moment it accepts.
33
+
34
+ Serves one connection per instance. TLS handshake failures (expected
35
+ when the client rejects the server certificate) are recorded in
36
+ tls_error rather than error so tearDown can ignore them.
37
+ """
38
+
39
+ def __init__(self):
40
+ self.error = None
41
+ self.tls_error = None
42
+ self.ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
43
+ self.ctx.load_cert_chain(str(SERVER_CERT), str(SERVER_KEY))
44
+ self.sock = socket.socket()
45
+ self.sock.bind(("127.0.0.1", 0))
46
+ self.sock.listen(1)
47
+ self.port = self.sock.getsockname()[1]
48
+ self.thread = threading.Thread(target=self._serve, daemon=True)
49
+ self.thread.start()
50
+
51
+ def _serve(self):
52
+ try:
53
+ conn, _ = self.sock.accept()
54
+ try:
55
+ conn = self.ctx.wrap_socket(conn, server_side=True)
56
+ except ssl.SSLError as e:
57
+ self.tls_error = e
58
+ conn.close()
59
+ return
60
+ conn.sendall(b"* OK [CAPABILITY " + CAPS + b"] fake server ready\r\n")
61
+ f = conn.makefile("rb")
62
+ while True:
63
+ line = f.readline()
64
+ if not line:
65
+ break
66
+ parts = line.split(None, 1)
67
+ tag = parts[0]
68
+ cmd = parts[1].strip().upper() if len(parts) > 1 else b""
69
+ if cmd.startswith(b"CAPABILITY"):
70
+ conn.sendall(b"* CAPABILITY " + CAPS + b"\r\n")
71
+ conn.sendall(tag + b" OK CAPABILITY completed\r\n")
72
+ elif cmd.startswith(b"LOGOUT"):
73
+ conn.sendall(b"* BYE fake server signing off\r\n")
74
+ conn.sendall(tag + b" OK LOGOUT completed\r\n")
75
+ conn.close()
76
+ return
77
+ else:
78
+ conn.sendall(tag + b" OK done\r\n")
79
+ except Exception as e:
80
+ self.error = e
81
+
82
+
83
+ @unittest.skipIf(
84
+ sys.version_info < (3, 9),
85
+ "imaplib.IMAP4 gained the timeout parameter in Python 3.9",
86
+ )
87
+ class TlsSocketTests(unittest.TestCase):
88
+ def setUp(self):
89
+ self.server = FakeTLSServer()
90
+ self._saved_cert_file = os.environ.pop("SSL_CERT_FILE", None)
91
+ os.environ["SSL_CERT_FILE"] = str(CA_FILE)
92
+
93
+ def tearDown(self):
94
+ if self._saved_cert_file is not None:
95
+ os.environ["SSL_CERT_FILE"] = self._saved_cert_file
96
+ self.server.sock.close()
97
+ self.assertIsNone(self.server.error)
98
+
99
+ def _client(self, **kwargs):
100
+ return IMAPClient("localhost", self.server.port, ssl=True, **kwargs)
101
+
102
+ def test_ssl_connect_with_default_context(self):
103
+ client = self._client()
104
+
105
+ sock = client._imap.sock
106
+ self.assertIsInstance(sock, ssl.SSLSocket)
107
+ # IMAPClient's documented default: hostname checking and certificate
108
+ # verification ON. imaplib's own None-fallback is unverified.
109
+ self.assertTrue(sock.context.check_hostname)
110
+ self.assertEqual(sock.context.verify_mode, ssl.CERT_REQUIRED)
111
+
112
+ self.assertIn(b"IMAP4REV1", client.capabilities())
113
+ client.login("user", "pass")
114
+ client.logout()
115
+
116
+ def test_ssl_connect_with_custom_context(self):
117
+ context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
118
+ context.check_hostname = False
119
+ context.verify_mode = ssl.CERT_NONE
120
+
121
+ client = self._client(ssl_context=context)
122
+
123
+ self.assertIs(client._imap.sock.context, context)
124
+ client.login("user", "pass")
125
+ client.logout()
126
+
127
+ def test_ssl_connect_untrusted_cert_fails(self):
128
+ # Without the test CA in the verification path, the default context
129
+ # must reject the server's self-signed certificate.
130
+ del os.environ["SSL_CERT_FILE"]
131
+
132
+ with self.assertRaises(ssl.SSLError):
133
+ self._client()
File without changes
File without changes
File without changes