python-socks 2.6.0__py3-none-any.whl → 2.7.0__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.
python_socks/_errors.py CHANGED
@@ -4,7 +4,7 @@ class ProxyError(Exception):
4
4
  self.error_code = error_code
5
5
 
6
6
 
7
- class ProxyTimeoutError(Exception):
7
+ class ProxyTimeoutError(TimeoutError):
8
8
  pass
9
9
 
10
10
 
python_socks/_version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  __title__ = 'python-socks'
2
- __version__ = '2.6.0'
2
+ __version__ = '2.7.0'
@@ -1,8 +1,14 @@
1
1
  from typing import Iterable
2
+ import warnings
2
3
 
3
4
 
4
5
  class ProxyChain:
5
6
  def __init__(self, proxies: Iterable):
7
+ warnings.warn(
8
+ 'This implementation of ProxyChain is deprecated and will be removed in the future',
9
+ DeprecationWarning,
10
+ stacklevel=2,
11
+ )
6
12
  self._proxies = proxies
7
13
 
8
14
  async def connect(self, dest_host, dest_port, timeout=None):
@@ -15,14 +21,14 @@ class ProxyChain:
15
21
  dest_host=proxies[i + 1].proxy_host,
16
22
  dest_port=proxies[i + 1].proxy_port,
17
23
  timeout=timeout,
18
- _socket=curr_socket
24
+ _socket=curr_socket,
19
25
  )
20
26
 
21
27
  curr_socket = await proxies[length].connect(
22
28
  dest_host=dest_host,
23
29
  dest_port=dest_port,
24
30
  timeout=timeout,
25
- _socket=curr_socket
31
+ _socket=curr_socket,
26
32
  )
27
33
 
28
34
  return curr_socket
@@ -1,9 +1,15 @@
1
1
  from typing import Iterable
2
+ import warnings
2
3
  from ._proxy import AnyioProxy
3
4
 
4
5
 
5
6
  class ProxyChain:
6
7
  def __init__(self, proxies: Iterable[AnyioProxy]):
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,3 +1,4 @@
1
+ from typing import Optional
1
2
  import anyio
2
3
  import anyio.abc
3
4
 
@@ -5,7 +6,7 @@ import anyio.abc
5
6
  async def connect_tcp(
6
7
  host: str,
7
8
  port: int,
8
- local_host: str = None,
9
+ local_host: Optional[str] = None,
9
10
  ) -> anyio.abc.SocketStream:
10
11
 
11
12
  return await anyio.connect_tcp(
@@ -1,5 +1,6 @@
1
1
  import ssl
2
2
  from typing import Any, Optional
3
+ import warnings
3
4
 
4
5
  import anyio
5
6
 
@@ -52,7 +53,14 @@ class AnyioProxy:
52
53
  timeout = DEFAULT_TIMEOUT
53
54
 
54
55
  _stream = kwargs.get('_stream')
55
-
56
+ if _stream is not None:
57
+ warnings.warn(
58
+ "The '_stream' argument is deprecated and will be removed in the future",
59
+ DeprecationWarning,
60
+ stacklevel=2,
61
+ )
62
+
63
+ local_host = kwargs.get('local_host')
56
64
  try:
57
65
  with anyio.fail_after(timeout):
58
66
  if _stream is None:
@@ -61,6 +69,7 @@ class AnyioProxy:
61
69
  await connect_tcp(
62
70
  host=self._proxy_host,
63
71
  port=self._proxy_port,
72
+ local_host=local_host,
64
73
  )
65
74
  )
66
75
  except OSError as e:
@@ -123,6 +132,6 @@ class AnyioProxy:
123
132
  return cls(*args, **kwargs)
124
133
 
125
134
  @classmethod
126
- def from_url(cls, url: str, **kwargs):
135
+ def from_url(cls, url: str, **kwargs) -> 'AnyioProxy':
127
136
  url_args = parse_proxy_url(url)
128
137
  return cls(*url_args, **kwargs)
@@ -1,9 +1,15 @@
1
1
  from typing import Sequence
2
+ import warnings
2
3
  from ._proxy import AnyioProxy
3
4
 
4
5
 
5
6
  class ProxyChain:
6
7
  def __init__(self, proxies: Sequence[AnyioProxy]):
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,3 +1,4 @@
1
+ from typing import Optional
1
2
  import anyio
2
3
  import anyio.abc
3
4
  from ._stream import AnyioSocketStream
@@ -6,7 +7,7 @@ from ._stream import AnyioSocketStream
6
7
  async def connect_tcp(
7
8
  host: str,
8
9
  port: int,
9
- local_host: str = None,
10
+ local_host: Optional[str] = None,
10
11
  ) -> AnyioSocketStream:
11
12
  s = await anyio.connect_tcp(
12
13
  remote_host=host,
@@ -1,5 +1,5 @@
1
1
  import ssl
2
- from typing import Optional
2
+ from typing import Any, Optional
3
3
 
4
4
  import anyio
5
5
 
@@ -47,33 +47,36 @@ class AnyioProxy:
47
47
  dest_port: int,
48
48
  dest_ssl: Optional[ssl.SSLContext] = None,
49
49
  timeout: Optional[float] = None,
50
+ **kwargs: Any,
50
51
  ) -> AnyioSocketStream:
51
52
  if timeout is None:
52
53
  timeout = DEFAULT_TIMEOUT
53
54
 
55
+ local_host = kwargs.get('local_host')
54
56
  try:
55
57
  with anyio.fail_after(timeout):
56
58
  return await self._connect(
57
59
  dest_host=dest_host,
58
60
  dest_port=dest_port,
59
61
  dest_ssl=dest_ssl,
62
+ local_host=local_host,
60
63
  )
61
64
  except TimeoutError as e:
62
- raise ProxyTimeoutError(
63
- 'Proxy connection timed out: {}'.format(timeout)
64
- ) from e
65
+ raise ProxyTimeoutError('Proxy connection timed out: {}'.format(timeout)) from e
65
66
 
66
67
  async def _connect(
67
68
  self,
68
69
  dest_host: str,
69
70
  dest_port: int,
70
71
  dest_ssl: Optional[ssl.SSLContext] = None,
72
+ local_host: Optional[str] = None,
71
73
  ) -> AnyioSocketStream:
72
74
  if self._forward is None:
73
75
  try:
74
76
  stream = await connect_tcp(
75
77
  host=self._proxy_host,
76
78
  port=self._proxy_port,
79
+ local_host=local_host,
77
80
  )
78
81
  except OSError as e:
79
82
  raise ProxyConnectionError(
@@ -127,6 +130,6 @@ class AnyioProxy:
127
130
  return cls(*args, **kwargs)
128
131
 
129
132
  @classmethod
130
- def from_url(cls, url: str, **kwargs):
133
+ def from_url(cls, url: str, **kwargs) -> 'AnyioProxy':
131
134
  url_args = parse_proxy_url(url)
132
135
  return cls(*url_args, **kwargs)
@@ -23,7 +23,7 @@ async def connect_tcp(
23
23
  if is_ipv6_address(host):
24
24
  address = (host, port, 0, 0) # to fix OSError: [WinError 10022]
25
25
  else:
26
- address = (host, port)
26
+ address = (host, port) # type: ignore[assignment]
27
27
 
28
28
  await loop.sock_connect(sock=sock, address=address)
29
29
  return sock
@@ -2,6 +2,7 @@ import asyncio
2
2
  import socket
3
3
  import sys
4
4
  from typing import Any, Optional
5
+ import warnings
5
6
 
6
7
  from ..._types import ProxyType
7
8
  from ..._helpers import parse_proxy_url
@@ -58,23 +59,39 @@ class AsyncioProxy:
58
59
  timeout = DEFAULT_TIMEOUT
59
60
 
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')
61
70
  try:
62
71
  async with async_timeout.timeout(timeout):
63
72
  return await self._connect(
64
73
  dest_host=dest_host,
65
74
  dest_port=dest_port,
66
75
  _socket=_socket,
76
+ local_addr=local_addr,
67
77
  )
68
78
  except asyncio.TimeoutError as e:
69
79
  raise ProxyTimeoutError(f'Proxy connection timed out: {timeout}') from e
70
80
 
71
- 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:
72
88
  if _socket is None:
73
89
  try:
74
90
  _socket = await connect_tcp(
75
91
  host=self._proxy_host,
76
92
  port=self._proxy_port,
77
93
  loop=self._loop,
94
+ local_addr=local_addr,
78
95
  )
79
96
  except OSError as e:
80
97
  msg = 'Could not connect to proxy {}:{} [{}]'.format(
@@ -101,42 +118,13 @@ class AsyncioProxy:
101
118
  )
102
119
 
103
120
  return _socket
104
- except asyncio.CancelledError: # pragma: no cover
105
- # https://bugs.python.org/issue30064
106
- # https://bugs.python.org/issue34795
107
- if self._can_be_closed_safely():
108
- await stream.close()
109
- raise
110
121
  except ReplyError as e:
111
122
  await stream.close()
112
123
  raise ProxyError(e, error_code=e.error_code)
113
- except Exception: # pragma: no cover
124
+ except (asyncio.CancelledError, Exception): # pragma: no cover
114
125
  await stream.close()
115
126
  raise
116
127
 
117
- def _can_be_closed_safely(self): # pragma: no cover
118
- def is_proactor_event_loop():
119
- try:
120
- # pylint:disable-next=import-outside-toplevel
121
- from asyncio import ProactorEventLoop
122
- except ImportError:
123
- return False
124
- return isinstance(self._loop, ProactorEventLoop)
125
-
126
- def is_uvloop_event_loop():
127
- try:
128
- # pylint:disable-next=import-outside-toplevel
129
- from uvloop import Loop # type:ignore[import-not-found]
130
- except ImportError:
131
- return False
132
- return isinstance(self._loop, Loop)
133
-
134
- return (
135
- sys.version_info[:2] >= (3, 8)
136
- or is_proactor_event_loop()
137
- or is_uvloop_event_loop()
138
- )
139
-
140
128
  @property
141
129
  def proxy_host(self):
142
130
  return self._proxy_host
@@ -150,6 +138,6 @@ class AsyncioProxy:
150
138
  return cls(*args, **kwargs)
151
139
 
152
140
  @classmethod
153
- def from_url(cls, url: str, **kwargs):
141
+ def from_url(cls, url: str, **kwargs) -> 'AsyncioProxy':
154
142
  url_args = parse_proxy_url(url)
155
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,6 +1,6 @@
1
1
  import asyncio
2
2
  import ssl
3
- from typing import Optional
3
+ from typing import Any, Optional, Tuple
4
4
  import warnings
5
5
  import sys
6
6
 
@@ -68,27 +68,29 @@ class AsyncioProxy:
68
68
  dest_port: int,
69
69
  dest_ssl: Optional[ssl.SSLContext] = None,
70
70
  timeout: Optional[float] = None,
71
+ **kwargs: Any,
71
72
  ) -> AsyncioSocketStream:
72
73
  if timeout is None:
73
74
  timeout = DEFAULT_TIMEOUT
74
75
 
76
+ local_addr = kwargs.get('local_addr')
75
77
  try:
76
78
  async with async_timeout.timeout(timeout):
77
79
  return await self._connect(
78
80
  dest_host=dest_host,
79
81
  dest_port=dest_port,
80
82
  dest_ssl=dest_ssl,
83
+ local_addr=local_addr,
81
84
  )
82
85
  except asyncio.TimeoutError as e:
83
- raise ProxyTimeoutError(
84
- 'Proxy connection timed out: {}'.format(timeout)
85
- ) from e
86
+ raise ProxyTimeoutError('Proxy connection timed out: {}'.format(timeout)) from e
86
87
 
87
88
  async def _connect(
88
89
  self,
89
90
  dest_host: str,
90
91
  dest_port: int,
91
92
  dest_ssl: Optional[ssl.SSLContext] = None,
93
+ local_addr: Optional[Tuple[str, int]] = None,
92
94
  ) -> AsyncioSocketStream:
93
95
  if self._forward is None:
94
96
  try:
@@ -96,6 +98,7 @@ class AsyncioProxy:
96
98
  host=self._proxy_host,
97
99
  port=self._proxy_port,
98
100
  loop=self._loop,
101
+ local_addr=local_addr,
99
102
  )
100
103
  except OSError as e:
101
104
  raise ProxyConnectionError(
@@ -149,6 +152,6 @@ class AsyncioProxy:
149
152
  return cls(*args, **kwargs)
150
153
 
151
154
  @classmethod
152
- def from_url(cls, url: str, **kwargs):
155
+ def from_url(cls, url: str, **kwargs) -> 'AsyncioProxy':
153
156
  url_args = parse_proxy_url(url)
154
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,4 +1,5 @@
1
1
  from typing import Any, Optional
2
+ import warnings
2
3
  import curio
3
4
  import curio.io
4
5
 
@@ -47,7 +48,14 @@ class CurioProxy:
47
48
  timeout = DEFAULT_TIMEOUT
48
49
 
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
+ )
50
57
 
58
+ local_addr = kwargs.get('local_addr')
51
59
  try:
52
60
  return await curio.timeout_after(
53
61
  timeout,
@@ -55,6 +63,7 @@ class CurioProxy:
55
63
  dest_host,
56
64
  dest_port,
57
65
  _socket,
66
+ local_addr,
58
67
  )
59
68
  except curio.TaskTimeout as e:
60
69
  raise ProxyTimeoutError(f'Proxy connection timed out: {timeout}') from e
@@ -64,12 +73,14 @@ class CurioProxy:
64
73
  dest_host: str,
65
74
  dest_port: int,
66
75
  _socket=None,
76
+ local_addr=None,
67
77
  ):
68
78
  if _socket is None:
69
79
  try:
70
80
  _socket = await connect_tcp(
71
81
  host=self._proxy_host,
72
82
  port=self._proxy_port,
83
+ local_addr=local_addr,
73
84
  )
74
85
  except OSError as e:
75
86
  msg = 'Could not connect to proxy {}:{} [{}]'.format(
@@ -116,6 +127,6 @@ class CurioProxy:
116
127
  return cls(*args, **kwargs)
117
128
 
118
129
  @classmethod
119
- def from_url(cls, url: str, **kwargs):
130
+ def from_url(cls, url: str, **kwargs) -> 'CurioProxy':
120
131
  url_args = parse_proxy_url(url)
121
132
  return cls(*url_args, **kwargs)
@@ -1,4 +1,5 @@
1
1
  from typing import Any, Optional
2
+ import warnings
2
3
  import trio
3
4
 
4
5
  from ..._types import ProxyType
@@ -46,30 +47,38 @@ class TrioProxy:
46
47
  timeout = DEFAULT_TIMEOUT
47
48
 
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
+ )
49
56
 
57
+ local_addr = kwargs.get('local_addr')
50
58
  try:
51
59
  with trio.fail_after(timeout):
52
60
  return await self._connect(
53
61
  dest_host=dest_host,
54
62
  dest_port=dest_port,
55
63
  _socket=_socket,
64
+ local_addr=local_addr,
56
65
  )
57
66
  except trio.TooSlowError as e:
58
- raise ProxyTimeoutError(
59
- 'Proxy connection timed out: {}'.format(timeout)
60
- ) from e
67
+ raise ProxyTimeoutError('Proxy connection timed out: {}'.format(timeout)) from e
61
68
 
62
69
  async def _connect(
63
70
  self,
64
71
  dest_host: str,
65
72
  dest_port: int,
66
73
  _socket=None,
74
+ local_addr=None,
67
75
  ) -> trio.socket.SocketType:
68
76
  if _socket is None:
69
77
  try:
70
78
  _socket = await connect_tcp(
71
79
  host=self._proxy_host,
72
80
  port=self._proxy_port,
81
+ local_addr=local_addr,
73
82
  )
74
83
  except OSError as e:
75
84
  msg = 'Could not connect to proxy {}:{} [{}]'.format(
@@ -117,6 +126,6 @@ class TrioProxy:
117
126
  return cls(*args, **kwargs)
118
127
 
119
128
  @classmethod
120
- def from_url(cls, url: str, **kwargs):
129
+ def from_url(cls, url: str, **kwargs) -> 'TrioProxy':
121
130
  url_args = parse_proxy_url(url)
122
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,5 +1,5 @@
1
1
  import ssl
2
- from typing import Optional
2
+ from typing import Any, Optional
3
3
 
4
4
  import trio
5
5
 
@@ -47,16 +47,19 @@ class TrioProxy:
47
47
  dest_port: int,
48
48
  dest_ssl: Optional[ssl.SSLContext] = None,
49
49
  timeout: Optional[float] = None,
50
+ **kwargs: Any,
50
51
  ) -> TrioSocketStream:
51
52
  if timeout is None:
52
53
  timeout = DEFAULT_TIMEOUT
53
54
 
55
+ local_addr = kwargs.get('local_addr')
54
56
  try:
55
57
  with trio.fail_after(timeout):
56
58
  return await self._connect(
57
59
  dest_host=dest_host,
58
60
  dest_port=dest_port,
59
61
  dest_ssl=dest_ssl,
62
+ local_addr=local_addr,
60
63
  )
61
64
  except trio.TooSlowError as e:
62
65
  raise ProxyTimeoutError(f'Proxy connection timed out: {timeout}') from e
@@ -66,12 +69,14 @@ class TrioProxy:
66
69
  dest_host: str,
67
70
  dest_port: int,
68
71
  dest_ssl: Optional[ssl.SSLContext] = None,
72
+ local_addr: Optional[str] = None,
69
73
  ) -> TrioSocketStream:
70
74
  if self._forward is None:
71
75
  try:
72
76
  stream = await connect_tcp(
73
77
  host=self._proxy_host,
74
78
  port=self._proxy_port,
79
+ local_addr=local_addr,
75
80
  )
76
81
  except OSError as e:
77
82
  raise ProxyConnectionError(
@@ -125,6 +130,6 @@ class TrioProxy:
125
130
  return cls(*args, **kwargs)
126
131
 
127
132
  @classmethod
128
- def from_url(cls, url: str, **kwargs):
133
+ def from_url(cls, url: str, **kwargs) -> 'TrioProxy':
129
134
  url_args = parse_proxy_url(url)
130
135
  return cls(*url_args, **kwargs)
@@ -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)
@@ -1,5 +1,6 @@
1
1
  import socket
2
2
  from typing import Optional, Any
3
+ import warnings
3
4
 
4
5
  from .._errors import ProxyConnectionError, ProxyTimeoutError, ProxyError
5
6
 
@@ -46,13 +47,21 @@ class SyncProxy:
46
47
  timeout = DEFAULT_TIMEOUT
47
48
 
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
+ )
49
56
 
50
57
  if _socket is None:
58
+ local_addr = kwargs.get('local_addr')
51
59
  try:
52
60
  _socket = connect_tcp(
53
61
  host=self._proxy_host,
54
62
  port=self._proxy_port,
55
63
  timeout=timeout,
64
+ local_addr=local_addr,
56
65
  )
57
66
  except OSError as e:
58
67
  msg = 'Could not connect to proxy {}:{} [{}]'.format(
@@ -81,9 +90,7 @@ class SyncProxy:
81
90
  return _socket
82
91
  except socket.timeout as e:
83
92
  stream.close()
84
- raise ProxyTimeoutError(
85
- 'Proxy connection timed out: {}'.format(timeout)
86
- ) from e
93
+ raise ProxyTimeoutError('Proxy connection timed out: {}'.format(timeout)) from e
87
94
  except ReplyError as e:
88
95
  stream.close()
89
96
  raise ProxyError(e, error_code=e.error_code)
@@ -104,6 +111,6 @@ class SyncProxy:
104
111
  return cls(*args, **kwargs)
105
112
 
106
113
  @classmethod
107
- def from_url(cls, url: str, **kwargs):
114
+ def from_url(cls, url: str, **kwargs) -> 'SyncProxy':
108
115
  url_args = parse_proxy_url(url)
109
116
  return cls(*url_args, **kwargs)
@@ -6,7 +6,7 @@ from ._stream import SyncSocketStream
6
6
  def connect_tcp(
7
7
  host: str,
8
8
  port: int,
9
- timeout: float = None,
9
+ timeout: Optional[float] = None,
10
10
  local_addr: Optional[Tuple[str, int]] = None,
11
11
  ) -> SyncSocketStream:
12
12
  address = (host, port)
@@ -1,6 +1,6 @@
1
1
  import socket
2
2
  import ssl
3
- from typing import Optional
3
+ from typing import Any, Optional
4
4
 
5
5
  from ._connect import connect_tcp
6
6
  from ._stream import SyncSocketStream
@@ -45,16 +45,19 @@ class SyncProxy:
45
45
  dest_port: int,
46
46
  dest_ssl: Optional[ssl.SSLContext] = None,
47
47
  timeout: Optional[float] = None,
48
+ **kwargs: Any,
48
49
  ) -> SyncSocketStream:
49
50
  if timeout is None:
50
51
  timeout = DEFAULT_TIMEOUT
51
52
 
52
53
  if self._forward is None:
54
+ local_addr = kwargs.get('local_addr')
53
55
  try:
54
56
  stream = connect_tcp(
55
57
  host=self._proxy_host,
56
58
  port=self._proxy_port,
57
59
  timeout=timeout,
60
+ local_addr=local_addr,
58
61
  )
59
62
  except OSError as e:
60
63
  msg = 'Could not connect to proxy {}:{} [{}]'.format(
@@ -109,10 +112,10 @@ class SyncProxy:
109
112
  raise
110
113
 
111
114
  @classmethod
112
- def create(cls, *args, **kwargs): # for backward compatibility
115
+ def create(cls, *args, **kwargs): # for backward compatibility
113
116
  return cls(*args, **kwargs)
114
117
 
115
118
  @classmethod
116
- def from_url(cls, url: str, **kwargs):
119
+ def from_url(cls, url: str, **kwargs) -> 'SyncProxy':
117
120
  url_args = parse_proxy_url(url)
118
121
  return cls(*url_args, **kwargs)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: python-socks
3
- Version: 2.6.0
3
+ Version: 2.7.0
4
4
  Summary: Proxy (SOCKS4, SOCKS5, HTTP CONNECT) client for Python
5
5
  Author-email: Roman Snegirev <snegiryev@gmail.com>
6
6
  License: Apache-2.0
@@ -1,9 +1,9 @@
1
1
  python_socks/__init__.py,sha256=gKywvwx_x4_0hWJEa2eif1dPzP9YeFXJdrNlHuvFmC8,367
2
2
  python_socks/_abc.py,sha256=_juTZE0iqoTChE53IHjBKEYFO-fxYZfPhdUc6EgFlwE,909
3
- python_socks/_errors.py,sha256=l2j03Zna_EJhNqF3yApTYuQ147BcY0k74pkT4HAlRp4,245
3
+ python_socks/_errors.py,sha256=UwMkTn-31DGdjQaL7Ba5ht3m1DUX0eqvC8MN-BXu4nE,248
4
4
  python_socks/_helpers.py,sha256=UacO07M9i8G8CfqzBYWnehgCTFbZTlwJWAsFoXR3mVk,2708
5
5
  python_socks/_types.py,sha256=dgQifNf2mIwdKoX7YmI91H_lUsW9-Y0ZkZGlIV6_NNw,90
6
- python_socks/_version.py,sha256=VDGUdSXYIOZqFTKm-y-mF5-8Rkwpzs--GH_DWxzC6pY,49
6
+ python_socks/_version.py,sha256=v_xFnDqx2HbR5X4wOkhcjLVGOzc8LujUaPTxoI9n5Aw,49
7
7
  python_socks/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  python_socks/_connectors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  python_socks/_connectors/abc.py,sha256=1fgjPiv64UAMiJDsJXYr-GofPGhuHTwTzaodQfrzf7Q,397
@@ -21,57 +21,57 @@ python_socks/_protocols/http.py,sha256=QhLHqBgc6DfsvC8AIhylN1tjfk7QzxgwemrK1LuL3
21
21
  python_socks/_protocols/socks4.py,sha256=j1Psqi3PDiKAF19g_Mh3sf_RwXu7o-8X7BqWOaoTbKE,3061
22
22
  python_socks/_protocols/socks5.py,sha256=1PEr1s4JxmpST9OYEeVgbidnV_d4Vb85JZHmWqK-r9c,9713
23
23
  python_socks/async_/__init__.py,sha256=TeBn5oirLy6aPoWcTc3OW9OxXh5Uv5LADwF_Y7f7HjY,64
24
- python_socks/async_/_proxy_chain.py,sha256=YZR5aNqqG358ynVe1F14k32hjK3yb19v_hh2On0gZ_I,781
24
+ python_socks/async_/_proxy_chain.py,sha256=TiG1Uu45anONWi2ZFj11w4-LrNbja8SbG27bWCX9Et4,987
25
25
  python_socks/async_/anyio/__init__.py,sha256=pZnrND4Qd-pIGg7KI1ML41kZNkWHmkd3vrvwZZIJyk4,106
26
- python_socks/async_/anyio/_chain.py,sha256=EOXAd2w7OYEKsfugkvQpGKETej_80VeyjmZfH1_ZYZE,895
27
- python_socks/async_/anyio/_connect.py,sha256=6Qr_gh3FkPlGm1GrQq0DC1QupvPdXnWKd-Fniu0Kn9c,268
28
- python_socks/async_/anyio/_proxy.py,sha256=VSKRUIGmZE3hZC0PU6eyhidMA1Q9UrWSYLGQJsXr320,3960
26
+ python_socks/async_/anyio/_chain.py,sha256=-d4sR-JM8Agh73rB8nK7DBcB9oqDgtx2GOTAx-SMslU,1099
27
+ python_socks/async_/anyio/_connect.py,sha256=dYx-X2rDDTe-mtLm6DTpV-gFB7Vt_OYS1Xs_4Ea9JZ4,306
28
+ python_socks/async_/anyio/_proxy.py,sha256=nWHzIFPYPXatmuVITdDWN6uoQe_P2Xm6NomgfgYm5UA,4322
29
29
  python_socks/async_/anyio/_resolver.py,sha256=LPRLmEzgKPGCqAbEMmLSMVtFkNVKha_2u08MhrZZ-CY,590
30
30
  python_socks/async_/anyio/_stream.py,sha256=OcCl4YkccA0-5hZh90CP4YmsBDLPwHpS3B0wCLytnAY,1614
31
31
  python_socks/async_/anyio/v2/__init__.py,sha256=4xgyAJHDGpRANYVNfpUdn3Zo8Ib_gREWH8bH4APycK4,117
32
- python_socks/async_/anyio/v2/_chain.py,sha256=baTCXD68hceOMWYITrUUSKv-B745RT4TdpQPDkSz68Y,593
33
- python_socks/async_/anyio/v2/_connect.py,sha256=wOOuUxURCjIWOH1pd8H6gr3XZ3VnvRtmsAh97M_ULEA,330
34
- python_socks/async_/anyio/v2/_proxy.py,sha256=lTIPQHTfGm8hV4N6gpbvC7QxxDBxrfi0EHuXqu-nWoA,3897
32
+ python_socks/async_/anyio/v2/_chain.py,sha256=NZ_9dA1AQrG3pBOnYBszbtD-Kse85bQ_dT33VtmGx3o,797
33
+ python_socks/async_/anyio/v2/_connect.py,sha256=_LF1f_cYJbfdSqkq-xEK4nF4l-bP5I1VWRFFyX1RH3Y,368
34
+ python_socks/async_/anyio/v2/_proxy.py,sha256=7F-Y_xhVcqGnKjUDVnjYNkyz5VEFJjzZhkl0Xklyj9U,4085
35
35
  python_socks/async_/anyio/v2/_stream.py,sha256=40D3Pmb0rryk9gaQlmjpAMdiJi5H5O0xbBseblGG1FY,1616
36
36
  python_socks/async_/asyncio/__init__.py,sha256=0WAM07vy0YvI8IhKGmaUA0GaNLHaG3l-4mnJVbfoqHE,65
37
- python_socks/async_/asyncio/_connect.py,sha256=niNKiz2o1kfeIPVR3kXW7YHZ2sTK_Uehgq9tmFwbp7w,1014
38
- python_socks/async_/asyncio/_proxy.py,sha256=dHBoSOZuxFux5pClhPy_4yGoi5VvkNI9gJsMUJy29Ac,4689
37
+ python_socks/async_/asyncio/_connect.py,sha256=gd2gzsp-RmbpMAPvEbG_bKyh1PRWemMajvBDg02G1hg,1042
38
+ python_socks/async_/asyncio/_proxy.py,sha256=HS1NfXZCYOZ2b4qUee01CwH4NF1OcXPzqYxEJXYJeT8,4120
39
39
  python_socks/async_/asyncio/_resolver.py,sha256=ROqOncuIub87J9_nMdvRTG_5zYOh8uafk265z0s2ORQ,681
40
40
  python_socks/async_/asyncio/_stream.py,sha256=RP7BIP9iFFy5nLRf9kHH7s1h_zPfo0yoEVKNpExqFcI,1021
41
41
  python_socks/async_/asyncio/v2/__init__.py,sha256=v9eJQeZ2yGJHeBQ0FYqNmIMCRrB547QqoAANHVBitxY,108
42
- python_socks/async_/asyncio/v2/_chain.py,sha256=Yle3F3TKEpCo9Snd-T5hRnmfn9iWj2VNLb3UHz6yNiU,607
43
- python_socks/async_/asyncio/v2/_connect.py,sha256=b3kQBR7L6wp-yvWVwtcdb4JUdQV04JW-DXF1g1P3gxI,587
44
- python_socks/async_/asyncio/v2/_proxy.py,sha256=hgm276siuUn4nO5gK2iEaS12arvmVex1-Tz4NWNW_TM,4505
45
- python_socks/async_/asyncio/v2/_stream.py,sha256=dOvZPMLd0lHeZwlJIL-bK-PQN9sjM6urA5AyFXxdaas,3834
42
+ python_socks/async_/asyncio/v2/_chain.py,sha256=KCtmKg0halaCIEqBY6JB-KGVNNiaa4APBb5l5z8kVPk,811
43
+ python_socks/async_/asyncio/v2/_connect.py,sha256=3yPmPCNmMKlCCZZCnNvydER3ilnfE5gTevzBN7IoGEE,603
44
+ python_socks/async_/asyncio/v2/_proxy.py,sha256=QPMx2nFeHCKObBkDqzONkgf2VLXdhuP-aMsBWAgdf-I,4714
45
+ python_socks/async_/asyncio/v2/_stream.py,sha256=YdpJap_Ax-7tJnA-AJ7nayZmD5lpem2UIPbUepnzqxM,2753
46
46
  python_socks/async_/curio/__init__.py,sha256=1OyhLhvLJ23iDROgyxGqQACice66SrIYCMqmwjw_dqY,63
47
47
  python_socks/async_/curio/_connect.py,sha256=u1HRJ8n3OZbux-wETO9HuqZv9By2LGhhSsM78gnxr_0,328
48
- python_socks/async_/curio/_proxy.py,sha256=2JRxx8SQvGPAHKGgf9OImH_X2Gfhxxzb5brNkmq7KhM,3241
48
+ python_socks/async_/curio/_proxy.py,sha256=_Qgodw62VPvt-5j1T34l7P52R5Bk4Crq97QJ0f1Qf10,3644
49
49
  python_socks/async_/curio/_resolver.py,sha256=_jDZq_lzTl_QihxH2HNEY_7_ELo-qmzG6IO5PNNEOek,722
50
50
  python_socks/async_/curio/_stream.py,sha256=sIAbwkPuiFF4c8cEs7exVdGb7cfFgoggKTV4LYqDcm0,855
51
51
  python_socks/async_/trio/__init__.py,sha256=Y68xwGqkXGKXHcwM6nvev6n2ChbFpBUFW0RzBrsIrug,61
52
52
  python_socks/async_/trio/_connect.py,sha256=uN_qwxLWdvy2zclPw5Z8R5TPqgT6jjzzTcSHd-xGFas,783
53
- python_socks/async_/trio/_proxy.py,sha256=F2jMJ_41__3YgNXrOWafgcZY0aW0g6c7rdJuIb7GbGk,3399
53
+ python_socks/async_/trio/_proxy.py,sha256=yp3NJOTAaw2ReXlPt4fBRY51Xqc1C3tf16H3v0XvlCg,3786
54
54
  python_socks/async_/trio/_resolver.py,sha256=uqBoTkbYpwwESoph2SmXRUUHM_DsT7dALQDmKqp-sco,591
55
55
  python_socks/async_/trio/_stream.py,sha256=xunx_XUiwH1pBLQjWbkqq3P92SeXaRypPMPRYwHOsPg,1003
56
56
  python_socks/async_/trio/v2/__init__.py,sha256=cd8Sc6NLmrUZewkqeDvnxmQqGZBKNuwYEEb4NMW2qo0,116
57
- python_socks/async_/trio/v2/_chain.py,sha256=sf32gS-flmzVe60b83LtwOhbzvlm1s7gPlgIpAbW1hM,591
58
- python_socks/async_/trio/v2/_connect.py,sha256=9B7cpLC9HqrXdW-61jA8hGRspHuIgaLTniZyCqpSiPE,379
59
- python_socks/async_/trio/v2/_proxy.py,sha256=8BmeQRJkxM1bMJFvWdQqeSs_MDRp3DIPsLBAtb6X_FU,3877
57
+ python_socks/async_/trio/v2/_chain.py,sha256=g9atl9HcWYrCHLCI8GtLR9GZC67sKiXEjcvGwZVGhDw,795
58
+ python_socks/async_/trio/v2/_connect.py,sha256=Nk0ipvuFFnzH-NPfXkX57I74-sbT6ks--ZgbfN3r42o,360
59
+ python_socks/async_/trio/v2/_proxy.py,sha256=9118wyv9SthZNVlvECfb3OfhrPMOFyyJSHhl7lG0TbI,4094
60
60
  python_socks/async_/trio/v2/_stream.py,sha256=wGB7sDjRO1ywVNjF_DFgdF2orjD3zrh8dPSmW9aBEV0,1475
61
61
  python_socks/sync/__init__.py,sha256=Dslh61MLGktjBK50UVGYjAQ-iGl8tjoLR93_-cvddWM,106
62
- python_socks/sync/_chain.py,sha256=TJeIQmvCw5Z0slBQOD0V9mibC5jbM9pDD_xjlyYgHFs,804
63
- python_socks/sync/_connect.py,sha256=5i834THkhSTOwgIvzWNihHYGwxNv7JIr3aCnaXU1SLY,334
64
- python_socks/sync/_proxy.py,sha256=A4FKY9a28zrTsNEJfy3tUjfGQvQcFKpq77Xce8OKBfw,2964
62
+ python_socks/sync/_chain.py,sha256=do_WtGenqKAG7B50nNZdltFqEQV8t-mSlGnMACNIwgE,973
63
+ python_socks/sync/_connect.py,sha256=N1Y-uQXkOiJ_dxkwWHw1fBliIQlTL47ydql7IvaSqm8,344
64
+ python_socks/sync/_proxy.py,sha256=Ny2QA8GI2aCUm0JL8IfY2j2IaXKzAZNp6bZeF7OmwYA,3287
65
65
  python_socks/sync/_resolver.py,sha256=2rf9-NdjRktYrab1Oyv9ZJLKByP95ysFmRE3TgjRCSA,547
66
66
  python_socks/sync/_stream.py,sha256=x01ovajA0DAjHkBCxpMeFaWYjns9BljgBQ-GGyBqrw4,818
67
67
  python_socks/sync/v2/__init__.py,sha256=eVZc6zh0pLhNMf_uSPZiH_1vNGEvedwzX5gObUSkRT8,116
68
68
  python_socks/sync/v2/_chain.py,sha256=IRVMioTVWwxylZ8maD5Gqxhhgw4VyrG5vo_hAOuEn8Q,579
69
- python_socks/sync/v2/_connect.py,sha256=eqMKsH2wVnGZhV24_t9QfsNhjbnKtnipj7wzSNctM3Q,410
70
- python_socks/sync/v2/_proxy.py,sha256=kklPAuHxhqJ9uwFgT-KLhPZxqOmonJcF6evpELvqCQU,3484
69
+ python_socks/sync/v2/_connect.py,sha256=QrZ1CZimYCUMUuaD8JdUblwlqlzIbqFrbsPwMzoxGkM,420
70
+ python_socks/sync/v2/_proxy.py,sha256=7FuO6wML0DkEonoGAprhTlVd8fazOgNeNrJyxABmP1Q,3621
71
71
  python_socks/sync/v2/_ssl_transport.py,sha256=MURwzvKu-S2-MI7o8KaZTvvBFOiiKIu5R0ERVIMvERE,6088
72
72
  python_socks/sync/v2/_stream.py,sha256=Jq89x1xmIX3L_v-WyS1nRTItjTnYTcDcfDblsANxfJI,1544
73
- python_socks-2.6.0.dist-info/LICENSE.txt,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
74
- python_socks-2.6.0.dist-info/METADATA,sha256=pTdgOXsEuObKYZAQkOOxpM1-2vAtF-klRPZtrqhSugQ,7964
75
- python_socks-2.6.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
76
- python_socks-2.6.0.dist-info/top_level.txt,sha256=7qyDAVwjTZ0sIYG1iatFbE-SLpWhONjaoMQ0Ib2DX0Q,13
77
- python_socks-2.6.0.dist-info/RECORD,,
73
+ python_socks-2.7.0.dist-info/LICENSE.txt,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
74
+ python_socks-2.7.0.dist-info/METADATA,sha256=9oFucZVJgmHybD1FBfPNxM3fEbheWmQpJkll1smw1mI,7964
75
+ python_socks-2.7.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
76
+ python_socks-2.7.0.dist-info/top_level.txt,sha256=7qyDAVwjTZ0sIYG1iatFbE-SLpWhONjaoMQ0Ib2DX0Q,13
77
+ python_socks-2.7.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5