Skip to content

Commit f467a99

Browse files
committed
feat: add playwright proxy formatter
1 parent 84936cb commit f467a99

File tree

2 files changed

+105
-20
lines changed

2 files changed

+105
-20
lines changed

proxyproviders/models/proxy.py

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ class ProxyFormat(Enum):
1919
AIOHTTP = "aiohttp"
2020
"""AIOHTTP format, for use in aiohttp library HTTP calls"""
2121

22+
PLAYWRIGHT = "playwright"
23+
"""Playwright format, for use in Playwright browser automation"""
24+
2225
URL = "url"
2326
"""URL format, for use in URL strings"""
2427

@@ -90,29 +93,51 @@ def format(
9093
>>> proxy.format(ProxyFormat.HTTPX)
9194
{'http://': 'http://user:[email protected]:8080', 'https://': 'http://user:[email protected]:8080'}
9295
"""
96+
# Convert to ProxyFormat enum, handling both string and enum inputs
9397
if isinstance(format_type, str):
94-
format_type = ProxyFormat(format_type)
98+
try:
99+
format_type = ProxyFormat(format_type)
100+
except ValueError:
101+
raise ValueError(
102+
f"Invalid format type: '{format_type}'. Valid options are: {[f.value for f in ProxyFormat]}"
103+
)
104+
elif not isinstance(format_type, ProxyFormat):
105+
raise ValueError(
106+
f"Invalid format type: {type(format_type).__name__}. Expected ProxyFormat enum or string."
107+
)
108+
109+
format_handlers = {
110+
ProxyFormat.URL: lambda: self.to_url(kwargs.get("protocol", "http")),
111+
ProxyFormat.REQUESTS: lambda: self._format_requests(kwargs),
112+
ProxyFormat.CURL: lambda: ["-x", self.to_url("http")],
113+
ProxyFormat.HTTPX: lambda: self._format_httpx(),
114+
ProxyFormat.AIOHTTP: lambda: self.to_url("http"),
115+
ProxyFormat.PLAYWRIGHT: lambda: self._format_playwright(),
116+
}
117+
118+
handler = format_handlers.get(format_type)
119+
if handler is None:
120+
raise ValueError(f"Unsupported format: {format_type}")
95121

96-
if format_type == ProxyFormat.URL:
97-
protocol = kwargs.get("protocol", "http")
98-
return self.to_url(protocol)
122+
return handler()
99123

100-
elif format_type == ProxyFormat.REQUESTS:
101-
protocols = kwargs.get("protocols", self.protocols or ["http", "https"])
102-
proxy_url = self.to_url("http")
103-
return {protocol: proxy_url for protocol in protocols}
124+
def _format_requests(self, kwargs):
125+
"""Format proxy for requests library."""
126+
protocols = kwargs.get("protocols", self.protocols or ["http", "https"])
127+
proxy_url = self.to_url("http")
128+
return {protocol: proxy_url for protocol in protocols}
104129

105-
elif format_type == ProxyFormat.CURL:
106-
return ["-x", self.to_url("http")]
130+
def _format_httpx(self):
131+
"""Format proxy for httpx library."""
132+
proxy_url = self.to_url("http")
133+
return {"http://": proxy_url, "https://": proxy_url}
107134

108-
elif format_type == ProxyFormat.HTTPX:
109-
# httpx uses 'http://' and 'https://' as keys
110-
proxy_url = self.to_url("http")
111-
return {"http://": proxy_url, "https://": proxy_url}
135+
def _format_playwright(self):
136+
"""Format proxy for Playwright."""
137+
playwright_proxy = {"server": f"{self.proxy_address}:{self.port}"}
112138

113-
elif format_type == ProxyFormat.AIOHTTP:
114-
# aiohttp takes a single URL string
115-
return self.to_url("http")
139+
if self.username and self.password:
140+
playwright_proxy["username"] = self.username
141+
playwright_proxy["password"] = self.password
116142

117-
else:
118-
raise ValueError(f"Unsupported format: {format_type}")
143+
return playwright_proxy

tests/test_proxy_model.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,62 @@ def test_format_aiohttp(self, sample_proxy):
141141
expected = "http://testuser:[email protected]:8080"
142142
assert result == expected
143143

144+
def test_format_playwright_with_auth(self, sample_proxy):
145+
"""Test format for Playwright with authentication."""
146+
result = sample_proxy.format(ProxyFormat.PLAYWRIGHT)
147+
expected = {
148+
"server": "192.168.1.100:8080",
149+
"username": "testuser",
150+
"password": "testpass",
151+
}
152+
assert result == expected
153+
154+
def test_format_playwright_without_auth(self, sample_proxy_no_protocols):
155+
"""Test format for Playwright with authentication (sample_proxy_no_protocols has auth)."""
156+
result = sample_proxy_no_protocols.format(ProxyFormat.PLAYWRIGHT)
157+
expected = {
158+
"server": "10.0.0.1:3128",
159+
"username": "user2",
160+
"password": "pass2",
161+
}
162+
assert result == expected
163+
164+
def test_format_playwright_empty_credentials(self):
165+
"""Test format for Playwright with empty username/password."""
166+
proxy = Proxy(
167+
id="no-auth",
168+
username="",
169+
password="",
170+
proxy_address="192.168.1.1",
171+
port=8080,
172+
)
173+
result = proxy.format(ProxyFormat.PLAYWRIGHT)
174+
expected = {"server": "192.168.1.1:8080"}
175+
assert result == expected
176+
177+
def test_format_playwright_none_credentials(self):
178+
"""Test format for Playwright with None username/password."""
179+
proxy = Proxy(
180+
id="none-auth",
181+
username=None,
182+
password=None,
183+
proxy_address="192.168.1.1",
184+
port=8080,
185+
)
186+
result = proxy.format(ProxyFormat.PLAYWRIGHT)
187+
expected = {"server": "192.168.1.1:8080"}
188+
assert result == expected
189+
190+
def test_format_playwright_string_format(self, sample_proxy):
191+
"""Test format for Playwright using string format."""
192+
result = sample_proxy.format("playwright")
193+
expected = {
194+
"server": "192.168.1.100:8080",
195+
"username": "testuser",
196+
"password": "testpass",
197+
}
198+
assert result == expected
199+
144200
def test_format_string_enum(self, sample_proxy):
145201
"""Test format with string instead of enum."""
146202
result = sample_proxy.format("requests")
@@ -152,7 +208,7 @@ def test_format_string_enum(self, sample_proxy):
152208

153209
def test_format_unsupported_format(self, sample_proxy):
154210
"""Test format with unsupported format type."""
155-
with pytest.raises(ValueError, match="is not a valid ProxyFormat"):
211+
with pytest.raises(ValueError, match="Invalid format type"):
156212
sample_proxy.format("unsupported")
157213

158214
def test_format_proxy_with_limited_protocols(self):
@@ -237,3 +293,7 @@ def test_all_format_types_work(self, sample_proxy):
237293
# AIOHTTP format returns string
238294
aiohttp_result = sample_proxy.format(ProxyFormat.AIOHTTP)
239295
assert isinstance(aiohttp_result, str)
296+
297+
# PLAYWRIGHT format returns dict
298+
playwright_result = sample_proxy.format(ProxyFormat.PLAYWRIGHT)
299+
assert isinstance(playwright_result, dict)

0 commit comments

Comments
 (0)