python-socks 2.5.3__py3-none-any.whl → 2.6.1__py3-none-any.whl

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 (44) hide show
  1. python_socks/_abc.py +3 -26
  2. python_socks/_connectors/factory_async.py +4 -3
  3. python_socks/_connectors/factory_sync.py +4 -3
  4. python_socks/_connectors/http_async.py +3 -2
  5. python_socks/_connectors/http_sync.py +3 -2
  6. python_socks/_connectors/socks4_async.py +3 -2
  7. python_socks/_connectors/socks4_sync.py +3 -2
  8. python_socks/_connectors/socks5_async.py +4 -3
  9. python_socks/_connectors/socks5_sync.py +4 -3
  10. python_socks/_helpers.py +17 -10
  11. python_socks/_protocols/http.py +3 -2
  12. python_socks/_protocols/socks4.py +2 -1
  13. python_socks/_protocols/socks5.py +7 -7
  14. python_socks/_version.py +1 -1
  15. python_socks/async_/_proxy_chain.py +9 -4
  16. python_socks/async_/anyio/_chain.py +6 -0
  17. python_socks/async_/anyio/_connect.py +2 -1
  18. python_socks/async_/anyio/_proxy.py +21 -10
  19. python_socks/async_/anyio/v2/_chain.py +6 -0
  20. python_socks/async_/anyio/v2/_connect.py +2 -1
  21. python_socks/async_/anyio/v2/_proxy.py +16 -10
  22. python_socks/async_/asyncio/_connect.py +1 -1
  23. python_socks/async_/asyncio/_proxy.py +35 -40
  24. python_socks/async_/asyncio/v2/_chain.py +6 -0
  25. python_socks/async_/asyncio/v2/_connect.py +1 -1
  26. python_socks/async_/asyncio/v2/_proxy.py +23 -16
  27. python_socks/async_/asyncio/v2/_stream.py +5 -45
  28. python_socks/async_/curio/_proxy.py +22 -9
  29. python_socks/async_/trio/_proxy.py +22 -9
  30. python_socks/async_/trio/v2/_chain.py +6 -0
  31. python_socks/async_/trio/v2/_connect.py +2 -2
  32. python_socks/async_/trio/v2/_proxy.py +16 -10
  33. python_socks/py.typed +0 -0
  34. python_socks/sync/_chain.py +8 -5
  35. python_socks/sync/_connect.py +1 -1
  36. python_socks/sync/_proxy.py +20 -9
  37. python_socks/sync/v2/_connect.py +1 -1
  38. python_socks/sync/v2/_proxy.py +14 -11
  39. {python_socks-2.5.3.dist-info → python_socks-2.6.1.dist-info}/METADATA +35 -16
  40. python_socks-2.6.1.dist-info/RECORD +77 -0
  41. {python_socks-2.5.3.dist-info → python_socks-2.6.1.dist-info}/WHEEL +1 -1
  42. python_socks-2.5.3.dist-info/RECORD +0 -76
  43. {python_socks-2.5.3.dist-info → python_socks-2.6.1.dist-info}/LICENSE.txt +0 -0
  44. {python_socks-2.5.3.dist-info → python_socks-2.6.1.dist-info}/top_level.txt +0 -0
@@ -1,11 +1,8 @@
1
1
  import asyncio
2
2
  import socket
3
3
  import sys
4
-
5
- if sys.version_info >= (3, 11):
6
- import asyncio as async_timeout
7
- else:
8
- import async_timeout
4
+ from typing import Any, Optional
5
+ import warnings
9
6
 
10
7
  from ..._types import ProxyType
11
8
  from ..._helpers import parse_proxy_url
@@ -17,21 +14,25 @@ from ..._protocols.errors import ReplyError
17
14
  from ..._connectors.factory_async import create_connector
18
15
 
19
16
  from ._connect import connect_tcp
20
- from ... import _abc as abc
17
+
18
+ if sys.version_info >= (3, 11):
19
+ import asyncio as async_timeout # pylint:disable=reimported
20
+ else:
21
+ import async_timeout
21
22
 
22
23
  DEFAULT_TIMEOUT = 60
23
24
 
24
25
 
25
- class AsyncioProxy(abc.AsyncProxy):
26
+ class AsyncioProxy:
26
27
  def __init__(
27
28
  self,
28
29
  proxy_type: ProxyType,
29
30
  host: str,
30
31
  port: int,
31
- username: str = None,
32
- password: str = None,
33
- rdns: bool = None,
34
- loop: asyncio.AbstractEventLoop = None,
32
+ username: Optional[str] = None,
33
+ password: Optional[str] = None,
34
+ rdns: Optional[bool] = None,
35
+ loop: Optional[asyncio.AbstractEventLoop] = None,
35
36
  ):
36
37
  if loop is None:
37
38
  loop = asyncio.get_event_loop()
@@ -51,29 +52,46 @@ class AsyncioProxy(abc.AsyncProxy):
51
52
  self,
52
53
  dest_host: str,
53
54
  dest_port: int,
54
- timeout: float = None,
55
- _socket=None,
55
+ timeout: Optional[float] = None,
56
+ **kwargs: Any,
56
57
  ) -> socket.socket:
57
58
  if timeout is None:
58
59
  timeout = DEFAULT_TIMEOUT
59
60
 
61
+ _socket = kwargs.get('_socket')
62
+ if _socket is not None:
63
+ warnings.warn(
64
+ "The '_socket' argument is deprecated and will be removed in the future",
65
+ DeprecationWarning,
66
+ stacklevel=2,
67
+ )
68
+
69
+ local_addr = kwargs.get('local_addr')
60
70
  try:
61
71
  async with async_timeout.timeout(timeout):
62
72
  return await self._connect(
63
73
  dest_host=dest_host,
64
74
  dest_port=dest_port,
65
75
  _socket=_socket,
76
+ local_addr=local_addr,
66
77
  )
67
78
  except asyncio.TimeoutError as e:
68
79
  raise ProxyTimeoutError(f'Proxy connection timed out: {timeout}') from e
69
80
 
70
- async def _connect(self, dest_host, dest_port, _socket=None) -> socket.socket:
81
+ async def _connect(
82
+ self,
83
+ dest_host,
84
+ dest_port,
85
+ _socket=None,
86
+ local_addr=None,
87
+ ) -> socket.socket:
71
88
  if _socket is None:
72
89
  try:
73
90
  _socket = await connect_tcp(
74
91
  host=self._proxy_host,
75
92
  port=self._proxy_port,
76
93
  loop=self._loop,
94
+ local_addr=local_addr,
77
95
  )
78
96
  except OSError as e:
79
97
  msg = 'Could not connect to proxy {}:{} [{}]'.format(
@@ -100,36 +118,13 @@ class AsyncioProxy(abc.AsyncProxy):
100
118
  )
101
119
 
102
120
  return _socket
103
- except asyncio.CancelledError: # pragma: no cover
104
- # https://bugs.python.org/issue30064
105
- # https://bugs.python.org/issue34795
106
- if self._can_be_closed_safely():
107
- await stream.close()
108
- raise
109
121
  except ReplyError as e:
110
122
  await stream.close()
111
123
  raise ProxyError(e, error_code=e.error_code)
112
- except Exception: # pragma: no cover
124
+ except (asyncio.CancelledError, Exception): # pragma: no cover
113
125
  await stream.close()
114
126
  raise
115
127
 
116
- def _can_be_closed_safely(self): # pragma: no cover
117
- def is_proactor_event_loop():
118
- try:
119
- from asyncio import ProactorEventLoop # noqa
120
- except ImportError:
121
- return False
122
- return isinstance(self._loop, ProactorEventLoop)
123
-
124
- def is_uvloop_event_loop():
125
- try:
126
- from uvloop import Loop # noqa
127
- except ImportError:
128
- return False
129
- return isinstance(self._loop, Loop)
130
-
131
- return sys.version_info[:2] >= (3, 8) or is_proactor_event_loop() or is_uvloop_event_loop()
132
-
133
128
  @property
134
129
  def proxy_host(self):
135
130
  return self._proxy_host
@@ -139,10 +134,10 @@ class AsyncioProxy(abc.AsyncProxy):
139
134
  return self._proxy_port
140
135
 
141
136
  @classmethod
142
- def create(cls, *args, **kwargs):
137
+ def create(cls, *args, **kwargs): # for backward compatibility
143
138
  return cls(*args, **kwargs)
144
139
 
145
140
  @classmethod
146
- def from_url(cls, url: str, **kwargs):
141
+ def from_url(cls, url: str, **kwargs) -> 'AsyncioProxy':
147
142
  url_args = parse_proxy_url(url)
148
143
  return cls(*url_args, **kwargs)
@@ -1,9 +1,15 @@
1
1
  from typing import Sequence
2
+ import warnings
2
3
  from ._proxy import AsyncioProxy
3
4
 
4
5
 
5
6
  class ProxyChain:
6
7
  def __init__(self, proxies: Sequence[AsyncioProxy]):
8
+ warnings.warn(
9
+ 'This implementation of ProxyChain is deprecated and will be removed in the future',
10
+ DeprecationWarning,
11
+ stacklevel=2,
12
+ )
7
13
  self._proxies = proxies
8
14
 
9
15
  async def connect(
@@ -16,7 +16,7 @@ async def connect_tcp(
16
16
  reader, writer = await asyncio.open_connection(
17
17
  host=host,
18
18
  port=port,
19
- **kwargs,
19
+ **kwargs, # type: ignore
20
20
  )
21
21
 
22
22
  return AsyncioSocketStream(
@@ -1,14 +1,10 @@
1
1
  import asyncio
2
2
  import ssl
3
+ from typing import Any, Optional, Tuple
3
4
  import warnings
4
5
  import sys
5
6
 
6
7
 
7
- if sys.version_info >= (3, 11):
8
- import asyncio as async_timeout
9
- else:
10
- import async_timeout
11
-
12
8
  from ...._types import ProxyType
13
9
  from ...._helpers import parse_proxy_url
14
10
  from ...._errors import ProxyConnectionError, ProxyTimeoutError, ProxyError
@@ -20,6 +16,12 @@ from .._resolver import Resolver
20
16
  from ._stream import AsyncioSocketStream
21
17
  from ._connect import connect_tcp
22
18
 
19
+ if sys.version_info >= (3, 11):
20
+ import asyncio as async_timeout # pylint:disable=reimported
21
+ else:
22
+ import async_timeout
23
+
24
+
23
25
  DEFAULT_TIMEOUT = 60
24
26
 
25
27
 
@@ -29,12 +31,12 @@ class AsyncioProxy:
29
31
  proxy_type: ProxyType,
30
32
  host: str,
31
33
  port: int,
32
- username: str = None,
33
- password: str = None,
34
- rdns: bool = None,
35
- proxy_ssl: ssl.SSLContext = None,
36
- forward: 'AsyncioProxy' = None,
37
- loop: asyncio.AbstractEventLoop = None,
34
+ username: Optional[str] = None,
35
+ password: Optional[str] = None,
36
+ rdns: Optional[bool] = None,
37
+ proxy_ssl: Optional[ssl.SSLContext] = None,
38
+ forward: Optional['AsyncioProxy'] = None,
39
+ loop: Optional[asyncio.AbstractEventLoop] = None,
38
40
  ):
39
41
  if loop is not None: # pragma: no cover
40
42
  warnings.warn(
@@ -64,18 +66,21 @@ class AsyncioProxy:
64
66
  self,
65
67
  dest_host: str,
66
68
  dest_port: int,
67
- dest_ssl: ssl.SSLContext = None,
68
- timeout: float = None,
69
+ dest_ssl: Optional[ssl.SSLContext] = None,
70
+ timeout: Optional[float] = None,
71
+ **kwargs: Any,
69
72
  ) -> AsyncioSocketStream:
70
73
  if timeout is None:
71
74
  timeout = DEFAULT_TIMEOUT
72
75
 
76
+ local_addr = kwargs.get('local_addr')
73
77
  try:
74
78
  async with async_timeout.timeout(timeout):
75
79
  return await self._connect(
76
80
  dest_host=dest_host,
77
81
  dest_port=dest_port,
78
82
  dest_ssl=dest_ssl,
83
+ local_addr=local_addr,
79
84
  )
80
85
  except asyncio.TimeoutError as e:
81
86
  raise ProxyTimeoutError('Proxy connection timed out: {}'.format(timeout)) from e
@@ -84,7 +89,8 @@ class AsyncioProxy:
84
89
  self,
85
90
  dest_host: str,
86
91
  dest_port: int,
87
- dest_ssl: ssl.SSLContext = None,
92
+ dest_ssl: Optional[ssl.SSLContext] = None,
93
+ local_addr: Optional[Tuple[str, int]] = None,
88
94
  ) -> AsyncioSocketStream:
89
95
  if self._forward is None:
90
96
  try:
@@ -92,6 +98,7 @@ class AsyncioProxy:
92
98
  host=self._proxy_host,
93
99
  port=self._proxy_port,
94
100
  loop=self._loop,
101
+ local_addr=local_addr,
95
102
  )
96
103
  except OSError as e:
97
104
  raise ProxyConnectionError(
@@ -141,10 +148,10 @@ class AsyncioProxy:
141
148
  return stream
142
149
 
143
150
  @classmethod
144
- def create(cls, *args, **kwargs):
151
+ def create(cls, *args, **kwargs): # for backward compatibility
145
152
  return cls(*args, **kwargs)
146
153
 
147
154
  @classmethod
148
- def from_url(cls, url: str, **kwargs):
155
+ def from_url(cls, url: str, **kwargs) -> 'AsyncioProxy':
149
156
  url_args = parse_proxy_url(url)
150
157
  return cls(*url_args, **kwargs)
@@ -6,48 +6,10 @@ from .... import _abc as abc
6
6
  DEFAULT_RECEIVE_SIZE = 65536
7
7
 
8
8
 
9
- # noinspection PyUnusedLocal
10
- async def backport_start_tls(
11
- transport,
12
- protocol,
13
- ssl_context,
14
- *,
15
- server_side=False,
16
- server_hostname=None,
17
- ssl_handshake_timeout=None,
18
- ): # pragma: no cover
19
- """
20
- Python 3.6 asyncio doesn't have a start_tls() method on the loop,
21
- so we use this function in place of the loop's start_tls() method.
22
- Adapted from this comment:
23
- https://github.com/urllib3/urllib3/issues/1323#issuecomment-362494839
24
- """
25
- import asyncio.sslproto
26
-
27
- loop = asyncio.get_event_loop()
28
- waiter = loop.create_future()
29
- ssl_protocol = asyncio.sslproto.SSLProtocol(
30
- loop,
31
- protocol,
32
- ssl_context,
33
- waiter,
34
- server_side=False,
35
- server_hostname=server_hostname,
36
- call_connection_made=False,
37
- )
38
-
39
- transport.set_protocol(ssl_protocol)
40
- loop.call_soon(ssl_protocol.connection_made, transport)
41
- loop.call_soon(transport.resume_reading) # type: ignore
42
-
43
- await waiter
44
- return ssl_protocol._app_transport # noqa
45
-
46
-
47
9
  class AsyncioSocketStream(abc.AsyncSocketStream):
48
- _loop: asyncio.AbstractEventLoop = None
49
- _reader: asyncio.StreamReader = None
50
- _writer: asyncio.StreamWriter = None
10
+ _loop: asyncio.AbstractEventLoop
11
+ _reader: asyncio.StreamReader
12
+ _writer: asyncio.StreamWriter
51
13
 
52
14
  def __init__(
53
15
  self,
@@ -86,9 +48,7 @@ class AsyncioSocketStream(abc.AsyncSocketStream):
86
48
  reader = asyncio.StreamReader()
87
49
  protocol = asyncio.StreamReaderProtocol(reader)
88
50
 
89
- loop_start_tls = getattr(self._loop, 'start_tls', backport_start_tls)
90
-
91
- transport = await loop_start_tls(
51
+ transport: asyncio.Transport = await self._loop.start_tls(
92
52
  self._writer.transport, # type: ignore
93
53
  protocol,
94
54
  ssl_context,
@@ -115,7 +75,7 @@ class AsyncioSocketStream(abc.AsyncSocketStream):
115
75
  # When we return a new SocketStream with new StreamReader/StreamWriter instances
116
76
  # we need to keep references to the old StreamReader/StreamWriter so that they
117
77
  # are not garbage collected and closed while we're still using them.
118
- stream._inner = self # type: ignore
78
+ stream._inner = self # type: ignore # pylint:disable=W0212,W0201
119
79
  return stream
120
80
 
121
81
  async def close(self):
@@ -1,3 +1,5 @@
1
+ from typing import Any, Optional
2
+ import warnings
1
3
  import curio
2
4
  import curio.io
3
5
 
@@ -12,20 +14,19 @@ from ._connect import connect_tcp
12
14
  from ..._protocols.errors import ReplyError
13
15
  from ..._connectors.factory_async import create_connector
14
16
 
15
- from ... import _abc as abc
16
17
 
17
18
  DEFAULT_TIMEOUT = 60
18
19
 
19
20
 
20
- class CurioProxy(abc.AsyncProxy):
21
+ class CurioProxy:
21
22
  def __init__(
22
23
  self,
23
24
  proxy_type: ProxyType,
24
25
  host: str,
25
26
  port: int,
26
- username: str = None,
27
- password: str = None,
28
- rdns: bool = None,
27
+ username: Optional[str] = None,
28
+ password: Optional[str] = None,
29
+ rdns: Optional[bool] = None,
29
30
  ):
30
31
  self._proxy_type = proxy_type
31
32
  self._proxy_host = host
@@ -40,12 +41,21 @@ class CurioProxy(abc.AsyncProxy):
40
41
  self,
41
42
  dest_host: str,
42
43
  dest_port: int,
43
- timeout: float = None,
44
- _socket=None,
44
+ timeout: Optional[float] = None,
45
+ **kwargs: Any,
45
46
  ) -> curio.io.Socket:
46
47
  if timeout is None:
47
48
  timeout = DEFAULT_TIMEOUT
48
49
 
50
+ _socket = kwargs.get('_socket')
51
+ if _socket is not None:
52
+ warnings.warn(
53
+ "The '_socket' argument is deprecated and will be removed in the future",
54
+ DeprecationWarning,
55
+ stacklevel=2,
56
+ )
57
+
58
+ local_addr = kwargs.get('local_addr')
49
59
  try:
50
60
  return await curio.timeout_after(
51
61
  timeout,
@@ -53,6 +63,7 @@ class CurioProxy(abc.AsyncProxy):
53
63
  dest_host,
54
64
  dest_port,
55
65
  _socket,
66
+ local_addr,
56
67
  )
57
68
  except curio.TaskTimeout as e:
58
69
  raise ProxyTimeoutError(f'Proxy connection timed out: {timeout}') from e
@@ -62,12 +73,14 @@ class CurioProxy(abc.AsyncProxy):
62
73
  dest_host: str,
63
74
  dest_port: int,
64
75
  _socket=None,
76
+ local_addr=None,
65
77
  ):
66
78
  if _socket is None:
67
79
  try:
68
80
  _socket = await connect_tcp(
69
81
  host=self._proxy_host,
70
82
  port=self._proxy_port,
83
+ local_addr=local_addr,
71
84
  )
72
85
  except OSError as e:
73
86
  msg = 'Could not connect to proxy {}:{} [{}]'.format(
@@ -110,10 +123,10 @@ class CurioProxy(abc.AsyncProxy):
110
123
  return self._proxy_port
111
124
 
112
125
  @classmethod
113
- def create(cls, *args, **kwargs):
126
+ def create(cls, *args, **kwargs): # for backward compatibility
114
127
  return cls(*args, **kwargs)
115
128
 
116
129
  @classmethod
117
- def from_url(cls, url: str, **kwargs):
130
+ def from_url(cls, url: str, **kwargs) -> 'CurioProxy':
118
131
  url_args = parse_proxy_url(url)
119
132
  return cls(*url_args, **kwargs)
@@ -1,3 +1,5 @@
1
+ from typing import Any, Optional
2
+ import warnings
1
3
  import trio
2
4
 
3
5
  from ..._types import ProxyType
@@ -11,20 +13,19 @@ from ._connect import connect_tcp
11
13
  from ..._protocols.errors import ReplyError
12
14
  from ..._connectors.factory_async import create_connector
13
15
 
14
- from ... import _abc as abc
15
16
 
16
17
  DEFAULT_TIMEOUT = 60
17
18
 
18
19
 
19
- class TrioProxy(abc.AsyncProxy):
20
+ class TrioProxy:
20
21
  def __init__(
21
22
  self,
22
23
  proxy_type: ProxyType,
23
24
  host: str,
24
25
  port: int,
25
- username: str = None,
26
- password: str = None,
27
- rdns: bool = None,
26
+ username: Optional[str] = None,
27
+ password: Optional[str] = None,
28
+ rdns: Optional[bool] = None,
28
29
  ):
29
30
  self._proxy_type = proxy_type
30
31
  self._proxy_host = host
@@ -39,18 +40,28 @@ class TrioProxy(abc.AsyncProxy):
39
40
  self,
40
41
  dest_host: str,
41
42
  dest_port: int,
42
- timeout: float = None,
43
- _socket=None,
43
+ timeout: Optional[float] = None,
44
+ **kwargs: Any,
44
45
  ) -> trio.socket.SocketType:
45
46
  if timeout is None:
46
47
  timeout = DEFAULT_TIMEOUT
47
48
 
49
+ _socket = kwargs.get('_socket')
50
+ if _socket is not None:
51
+ warnings.warn(
52
+ "The '_socket' argument is deprecated and will be removed in the future",
53
+ DeprecationWarning,
54
+ stacklevel=2,
55
+ )
56
+
57
+ local_addr = kwargs.get('local_addr')
48
58
  try:
49
59
  with trio.fail_after(timeout):
50
60
  return await self._connect(
51
61
  dest_host=dest_host,
52
62
  dest_port=dest_port,
53
63
  _socket=_socket,
64
+ local_addr=local_addr,
54
65
  )
55
66
  except trio.TooSlowError as e:
56
67
  raise ProxyTimeoutError('Proxy connection timed out: {}'.format(timeout)) from e
@@ -60,12 +71,14 @@ class TrioProxy(abc.AsyncProxy):
60
71
  dest_host: str,
61
72
  dest_port: int,
62
73
  _socket=None,
74
+ local_addr=None,
63
75
  ) -> trio.socket.SocketType:
64
76
  if _socket is None:
65
77
  try:
66
78
  _socket = await connect_tcp(
67
79
  host=self._proxy_host,
68
80
  port=self._proxy_port,
81
+ local_addr=local_addr,
69
82
  )
70
83
  except OSError as e:
71
84
  msg = 'Could not connect to proxy {}:{} [{}]'.format(
@@ -109,10 +122,10 @@ class TrioProxy(abc.AsyncProxy):
109
122
  return self._proxy_port
110
123
 
111
124
  @classmethod
112
- def create(cls, *args, **kwargs):
125
+ def create(cls, *args, **kwargs): # for backward compatibility
113
126
  return cls(*args, **kwargs)
114
127
 
115
128
  @classmethod
116
- def from_url(cls, url: str, **kwargs):
129
+ def from_url(cls, url: str, **kwargs) -> 'TrioProxy':
117
130
  url_args = parse_proxy_url(url)
118
131
  return cls(*url_args, **kwargs)
@@ -1,9 +1,15 @@
1
1
  from typing import Sequence
2
+ import warnings
2
3
  from ._proxy import TrioProxy
3
4
 
4
5
 
5
6
  class ProxyChain:
6
7
  def __init__(self, proxies: Sequence[TrioProxy]):
8
+ warnings.warn(
9
+ 'This implementation of ProxyChain is deprecated and will be removed in the future',
10
+ DeprecationWarning,
11
+ stacklevel=2,
12
+ )
7
13
  self._proxies = proxies
8
14
 
9
15
  async def connect(
@@ -1,4 +1,4 @@
1
- from typing import Optional, Tuple
1
+ from typing import Optional
2
2
 
3
3
  import trio
4
4
  from ._stream import TrioSocketStream
@@ -7,7 +7,7 @@ from ._stream import TrioSocketStream
7
7
  async def connect_tcp(
8
8
  host: str,
9
9
  port: int,
10
- local_addr: Optional[Tuple[str, int]] = None,
10
+ local_addr: Optional[str] = None,
11
11
  ) -> TrioSocketStream:
12
12
  trio_stream = await trio.open_tcp_stream(
13
13
  host=host,
@@ -1,4 +1,5 @@
1
1
  import ssl
2
+ from typing import Any, Optional
2
3
 
3
4
  import trio
4
5
 
@@ -22,11 +23,11 @@ class TrioProxy:
22
23
  proxy_type: ProxyType,
23
24
  host: str,
24
25
  port: int,
25
- username: str = None,
26
- password: str = None,
27
- rdns: bool = None,
28
- proxy_ssl: ssl.SSLContext = None,
29
- forward: 'TrioProxy' = None,
26
+ username: Optional[str] = None,
27
+ password: Optional[str] = None,
28
+ rdns: Optional[bool] = None,
29
+ proxy_ssl: Optional[ssl.SSLContext] = None,
30
+ forward: Optional['TrioProxy'] = None,
30
31
  ):
31
32
  self._proxy_type = proxy_type
32
33
  self._proxy_host = host
@@ -44,18 +45,21 @@ class TrioProxy:
44
45
  self,
45
46
  dest_host: str,
46
47
  dest_port: int,
47
- dest_ssl: ssl.SSLContext = None,
48
- timeout: float = None,
48
+ dest_ssl: Optional[ssl.SSLContext] = None,
49
+ timeout: Optional[float] = None,
50
+ **kwargs: Any,
49
51
  ) -> TrioSocketStream:
50
52
  if timeout is None:
51
53
  timeout = DEFAULT_TIMEOUT
52
54
 
55
+ local_addr = kwargs.get('local_addr')
53
56
  try:
54
57
  with trio.fail_after(timeout):
55
58
  return await self._connect(
56
59
  dest_host=dest_host,
57
60
  dest_port=dest_port,
58
61
  dest_ssl=dest_ssl,
62
+ local_addr=local_addr,
59
63
  )
60
64
  except trio.TooSlowError as e:
61
65
  raise ProxyTimeoutError(f'Proxy connection timed out: {timeout}') from e
@@ -64,13 +68,15 @@ class TrioProxy:
64
68
  self,
65
69
  dest_host: str,
66
70
  dest_port: int,
67
- dest_ssl: ssl.SSLContext = None,
71
+ dest_ssl: Optional[ssl.SSLContext] = None,
72
+ local_addr: Optional[str] = None,
68
73
  ) -> TrioSocketStream:
69
74
  if self._forward is None:
70
75
  try:
71
76
  stream = await connect_tcp(
72
77
  host=self._proxy_host,
73
78
  port=self._proxy_port,
79
+ local_addr=local_addr,
74
80
  )
75
81
  except OSError as e:
76
82
  raise ProxyConnectionError(
@@ -120,10 +126,10 @@ class TrioProxy:
120
126
  return stream
121
127
 
122
128
  @classmethod
123
- def create(cls, *args, **kwargs):
129
+ def create(cls, *args, **kwargs): # for backward compatibility
124
130
  return cls(*args, **kwargs)
125
131
 
126
132
  @classmethod
127
- def from_url(cls, url: str, **kwargs):
133
+ def from_url(cls, url: str, **kwargs) -> 'TrioProxy':
128
134
  url_args = parse_proxy_url(url)
129
135
  return cls(*url_args, **kwargs)
python_socks/py.typed ADDED
File without changes
@@ -1,9 +1,15 @@
1
1
  from typing import Iterable
2
+ import warnings
2
3
  from ._proxy import SyncProxy
3
4
 
4
5
 
5
6
  class ProxyChain:
6
7
  def __init__(self, proxies: Iterable[SyncProxy]):
8
+ warnings.warn(
9
+ 'This implementation of ProxyChain is deprecated and will be removed in the future',
10
+ DeprecationWarning,
11
+ stacklevel=2,
12
+ )
7
13
  self._proxies = proxies
8
14
 
9
15
  def connect(self, dest_host, dest_port, timeout=None):
@@ -16,14 +22,11 @@ class ProxyChain:
16
22
  dest_host=proxies[i + 1].proxy_host,
17
23
  dest_port=proxies[i + 1].proxy_port,
18
24
  timeout=timeout,
19
- _socket=curr_socket
25
+ _socket=curr_socket,
20
26
  )
21
27
 
22
28
  curr_socket = proxies[length].connect(
23
- dest_host=dest_host,
24
- dest_port=dest_port,
25
- timeout=timeout,
26
- _socket=curr_socket
29
+ dest_host=dest_host, dest_port=dest_port, timeout=timeout, _socket=curr_socket
27
30
  )
28
31
 
29
32
  return curr_socket
@@ -5,7 +5,7 @@ from typing import Optional, Tuple
5
5
  def connect_tcp(
6
6
  host: str,
7
7
  port: int,
8
- timeout: float = None,
8
+ timeout: Optional[float] = None,
9
9
  local_addr: Optional[Tuple[str, int]] = None,
10
10
  ) -> socket.socket:
11
11
  address = (host, port)