Skip to content
This repository was archived by the owner on Nov 5, 2023. It is now read-only.

Commit 2fb6d09

Browse files
Switched over from strings for options to using Enums to try and enforce correct options better
1 parent 62ae98b commit 2fb6d09

File tree

5 files changed

+45
-32
lines changed

5 files changed

+45
-32
lines changed

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,24 @@ Without an API key pubproxy limits users to one request per second so a `ProxyFe
2727
## Quickstart Example
2828

2929
```python
30-
from pubproxpy import ProxyFetcher
30+
from pubproxpy import Level, Protocol, ProxyFetcher
3131

3232
# ProxyFetcher for proxies that use the socks5 protocol, are located in
3333
# the US or Canada and support POST requests
34-
socks_pf = ProxyFetcher(protocol="socks5", countries=["US", "CA"], post=True)
34+
socks_pf = ProxyFetcher(
35+
protocol=Protocol.SOCKS5, countries=["US", "CA"], post=True
36+
)
3537

3638
# ProxyFetcher for proxies that support https, are elite anonymity level,
3739
# and connected in 15 seconds or less
3840
https_pf = ProxyFetcher(
39-
protocol="http", https=True, level="elite", time_to_connect=15
41+
protocol=Protocol.HTTP, https=True, level=Level.ELITE, time_to_connect=15
4042
)
4143

4244
# Get one socks proxy, followed by 10 https proxies
4345
# NOTE: even though there are multiple `ProxyFetcher`s the delays are
4446
# coordinated between them to prevent rate limiting
45-
socks_proxy = socks_pf.get()[0] # Get a single socks proxy
47+
socks_proxy = socks_pf.get()[0] # Get a single socks proxy
4648
https_proxies = https_pf.get(10) # Get a 10 https proxies
4749

4850
# And then if you want to get any remaining proxies left over before you're
@@ -64,8 +66,8 @@ Since the API doesn't check pretty much anything for correctness, we do our best
6466
|:--|:--|:--|
6567
|`exclude_used`|`bool` |[_Default: `True`_] If the `ProxyFetcher` should prevent re-returning proxies|
6668
|`api_key`|`str`|API key for a paid account, you can also set `$PUBPROXY_API_KEY` to pass your key, passing the `api_key` parameter will override the env-var if both are present|
67-
|`level`|`str`|[_Options: `"anonymous"`, `"elite"`_] Proxy anonymity level|
68-
|`protocol`|`str`|[_Options: `"http"`, `"socks4"`, `"socks5"`_] Desired communication protocol|
69+
|`level`|`pubproxpy.Level`|[_Options: `ANONYMOUS`, `ELITE`_] Proxy anonymity level|
70+
|`protocol`|`pubproxpy.Protocol`|[_Options: `HTTP`, `SOCKS4`, `SOCKS5`_] Desired communication protocol|
6971
|`countries`|`str` or `list<str>`|Locations of the proxy using the [ISO-3166 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country code, **Incompatible with `not_countries`**|
7072
|`not_countries`|`str` or `list<str>`|Blacklist locations of the proxy using the [ISO-3166 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country code, **Incompatible with `countries`**|
7173
|`last_checked`|`int`|[_Bounds: 1-1000_] Minutes since the proxy was checked|

pubproxpy/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from pubproxpy.fetcher import ProxyFetcher
2+
from pubproxpy.types import Level, Protocol
23

34

4-
__all__ = ["ProxyFetcher"]
5+
__all__ = ["ProxyFetcher", "Level", "Protocol"]
56
__version__ = "1.1.3"

pubproxpy/fetcher.py

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
#!/usr/bin/env python3
2-
# TODO: check for error with using a proxy to get proxies
3-
# TODO: `rg` to find any other todos before release
4-
# TODO: strongly type parameters
5-
61
import requests
72

83
from datetime import datetime as dt
@@ -13,6 +8,7 @@
138

149
from pubproxpy._singleton import Singleton
1510
from pubproxpy.errors import ProxyError, API_ERROR_MAP
11+
from pubproxpy.types import Level, Protocol
1612

1713

1814
class _FetcherShared(metaclass=Singleton):
@@ -30,9 +26,6 @@ def reset(self):
3026
self.__init__()
3127

3228

33-
# TODO: set up tests for things
34-
# TODO: move all the constants for ProxyFetcher outside of the class?
35-
# to constants file maybe?
3629
class ProxyFetcher:
3730
"""Class used to fetch proxies from the pubproxy API matching the provided
3831
parameters
@@ -58,12 +51,6 @@ class ProxyFetcher:
5851
"user_agent",
5952
)
6053

61-
# Parameters that have explicit options
62-
_PARAM_OPTS = {
63-
"level": ("anonymous", "elite"),
64-
"protocol": ("http", "socks4", "socks5"),
65-
}
66-
6754
# Parameters that are bounded
6855
_PARAM_BOUNDS = {"last_checked": (1, 1000), "time_to_connect": (1, 60)}
6956

@@ -112,6 +99,16 @@ def _verify_params(self, params):
11299
" mutually exclusive"
113100
)
114101

102+
# Check that protocol and level are the correct type
103+
for key, enum_type in (("protocol", Protocol), ("level", Level)):
104+
if key in params:
105+
val = params[key]
106+
if not isinstance(val, enum_type):
107+
raise ValueError(
108+
f"{key} should be of type `{enum_type}` not "
109+
f" `{type(val)}`"
110+
)
111+
115112
# Verify all params are valid, and satisfy the valid bounds or options
116113
for param, val in params.items():
117114
if param not in self._PARAMS:
@@ -120,14 +117,6 @@ def _verify_params(self, params):
120117
f" {[p for p in self._PARAMS]}"
121118
)
122119

123-
if param in self._PARAM_OPTS:
124-
opts = self._PARAM_OPTS[param]
125-
if val not in opts:
126-
raise ValueError(
127-
f'invalid value "{val}" for "{param}" options are'
128-
f" {opts}"
129-
)
130-
131120
if param in self._PARAM_BOUNDS:
132121
low, high = self._PARAM_BOUNDS[param]
133122
if val < low or val > high:
@@ -177,6 +166,11 @@ def _format_params(self, params):
177166
if isinstance(params["not_country"], (list, tuple)):
178167
params["not_country"] = ",".join(params["not_country"])
179168

169+
# Get value from enums
170+
for key in ("level", "type"):
171+
if key in params:
172+
params[key] = params[key].value
173+
180174
return params
181175

182176
def drain(self):

pubproxpy/types.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from enum import Enum
2+
3+
4+
class Level(Enum):
5+
ANONYMOUS = "anonymous"
6+
ELITE = "elite"
7+
8+
9+
class Protocol(Enum):
10+
HTTP = "http"
11+
SOCKS4 = "socks4"
12+
SOCKS5 = "socks5"

tests/test_fetcher.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import os
77
from unittest.mock import patch
88

9-
from pubproxpy import ProxyFetcher
9+
from pubproxpy import Level, Protocol, ProxyFetcher
1010
from pubproxpy.fetcher import _FetcherShared
1111

1212

@@ -94,11 +94,15 @@ def test_params():
9494
with pytest.raises(ValueError):
9595
_ = ProxyFetcher(countries="US", not_countries=["CA", "NK"])
9696

97+
# Switched from strings to `Enum`s when possible
98+
with pytest.raises(ValueError):
99+
_ = ProxyFetcher(protocol="http")
100+
97101
# And now it's time to check everything
98102
before_params = {
99103
"api_key": "<other key>",
100-
"level": "elite",
101-
"protocol": "http",
104+
"level": Level.ELITE,
105+
"protocol": Protocol.HTTP,
102106
"countries": "CA",
103107
"last_checked": 1,
104108
"port": 1234,

0 commit comments

Comments
 (0)