smooth-py 0.3.0.post2__tar.gz → 0.3.1.dev20251027__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.
Potentially problematic release.
This version of smooth-py might be problematic. Click here for more details.
- {smooth_py-0.3.0.post2 → smooth_py-0.3.1.dev20251027}/PKG-INFO +1 -1
- {smooth_py-0.3.0.post2 → smooth_py-0.3.1.dev20251027}/pyproject.toml +1 -1
- {smooth_py-0.3.0.post2 → smooth_py-0.3.1.dev20251027}/src/smooth/__init__.py +66 -2
- {smooth_py-0.3.0.post2 → smooth_py-0.3.1.dev20251027}/README.md +0 -0
- {smooth_py-0.3.0.post2 → smooth_py-0.3.1.dev20251027}/src/smooth/mcp/__init__.py +0 -0
- {smooth_py-0.3.0.post2 → smooth_py-0.3.1.dev20251027}/src/smooth/mcp/server.py +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Smooth python SDK."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import base64
|
|
4
5
|
import io
|
|
5
6
|
import logging
|
|
6
7
|
import os
|
|
@@ -8,7 +9,7 @@ import time
|
|
|
8
9
|
import urllib.parse
|
|
9
10
|
import warnings
|
|
10
11
|
from pathlib import Path
|
|
11
|
-
from typing import Any, Literal, Type
|
|
12
|
+
from typing import Any, Literal, NotRequired, Type, TypedDict
|
|
12
13
|
|
|
13
14
|
import httpx
|
|
14
15
|
import requests
|
|
@@ -33,7 +34,47 @@ def _encode_url(url: str, interactive: bool = True, embed: bool = False) -> str:
|
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
# --- Models ---
|
|
36
|
-
|
|
37
|
+
|
|
38
|
+
class Certificate(TypedDict):
|
|
39
|
+
"""Client certificate for accessing secure websites.
|
|
40
|
+
|
|
41
|
+
Attributes:
|
|
42
|
+
file: p12 file object to be uploaded (e.g., open("cert.p12", "rb")).
|
|
43
|
+
password: Password to decrypt the certificate file. Optional.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
file: str | io.IOBase # Required - base64 string or binary IO
|
|
47
|
+
password: NotRequired[str] # Optional
|
|
48
|
+
filters: NotRequired[list[str]] # Optional - TODO: Reserved for future use to specify URL patterns where the certificate should be applied.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _process_certificates(certificates: list[Certificate] | None) -> list[dict[str, Any]] | None:
|
|
52
|
+
"""Process certificates, converting binary IO to base64-encoded strings.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
certificates: List of certificates with file field as string or binary IO.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
List of certificates with file field as base64-encoded string, or None if input is None.
|
|
59
|
+
"""
|
|
60
|
+
if certificates is None:
|
|
61
|
+
return None
|
|
62
|
+
|
|
63
|
+
processed_certs = []
|
|
64
|
+
for cert in certificates:
|
|
65
|
+
processed_cert = dict(cert) # Create a copy
|
|
66
|
+
|
|
67
|
+
file_content = processed_cert["file"]
|
|
68
|
+
if isinstance(file_content, io.IOBase):
|
|
69
|
+
# Read the binary content and encode to base64
|
|
70
|
+
binary_data = file_content.read()
|
|
71
|
+
processed_cert["file"] = base64.b64encode(binary_data).decode("utf-8")
|
|
72
|
+
elif not isinstance(file_content, str):
|
|
73
|
+
raise TypeError(f"Certificate file must be a string or binary IO, got {type(file_content)}")
|
|
74
|
+
|
|
75
|
+
processed_certs.append(processed_cert)
|
|
76
|
+
|
|
77
|
+
return processed_certs
|
|
37
78
|
|
|
38
79
|
|
|
39
80
|
class TaskResponse(BaseModel):
|
|
@@ -48,6 +89,7 @@ class TaskResponse(BaseModel):
|
|
|
48
89
|
device: Literal["desktop", "mobile"] | None = Field(default=None, description="The device type used for the task.")
|
|
49
90
|
live_url: str | None = Field(default=None, description="The URL to view and interact with the task execution.")
|
|
50
91
|
recording_url: str | None = Field(default=None, description="The URL to view the task recording.")
|
|
92
|
+
created_at: int | None = Field(default=None, description="The timestamp when the task was created.")
|
|
51
93
|
|
|
52
94
|
|
|
53
95
|
class TaskRequest(BaseModel):
|
|
@@ -97,6 +139,15 @@ class TaskRequest(BaseModel):
|
|
|
97
139
|
)
|
|
98
140
|
proxy_username: str | None = Field(default=None, description="Proxy server username.")
|
|
99
141
|
proxy_password: str | None = Field(default=None, description="Proxy server password.")
|
|
142
|
+
certificates: list[dict[str, Any]] | None = Field(
|
|
143
|
+
default=None,
|
|
144
|
+
description=(
|
|
145
|
+
"List of client certificates to use when accessing secure websites. "
|
|
146
|
+
"Each certificate is a dictionary with the following fields:\n"
|
|
147
|
+
" - `file`: p12 file object to be uploaded (e.g., open('cert.p12', 'rb')).\n"
|
|
148
|
+
" - `password` (optional): Password to decrypt the certificate file."
|
|
149
|
+
),
|
|
150
|
+
)
|
|
100
151
|
experimental_features: dict[str, Any] | None = Field(
|
|
101
152
|
default=None, description="Experimental features to enable for the task."
|
|
102
153
|
)
|
|
@@ -490,6 +541,7 @@ class SmoothClient(BaseClient):
|
|
|
490
541
|
proxy_server: str | None = None,
|
|
491
542
|
proxy_username: str | None = None,
|
|
492
543
|
proxy_password: str | None = None,
|
|
544
|
+
certificates: list[Certificate] | None = None,
|
|
493
545
|
experimental_features: dict[str, Any] | None = None,
|
|
494
546
|
) -> TaskHandle:
|
|
495
547
|
"""Runs a task and returns a handle to the task.
|
|
@@ -516,6 +568,10 @@ class SmoothClient(BaseClient):
|
|
|
516
568
|
proxy_server: Proxy server url to route browser traffic through.
|
|
517
569
|
proxy_username: Proxy server username.
|
|
518
570
|
proxy_password: Proxy server password.
|
|
571
|
+
certificates: List of client certificates to use when accessing secure websites.
|
|
572
|
+
Each certificate is a dictionary with the following fields:
|
|
573
|
+
- `file` (required): p12 file object to be uploaded (e.g., open("cert.p12", "rb")).
|
|
574
|
+
- `password` (optional): Password to decrypt the certificate file, if password-protected.
|
|
519
575
|
experimental_features: Experimental features to enable for the task.
|
|
520
576
|
|
|
521
577
|
Returns:
|
|
@@ -541,6 +597,7 @@ class SmoothClient(BaseClient):
|
|
|
541
597
|
proxy_server=proxy_server,
|
|
542
598
|
proxy_username=proxy_username,
|
|
543
599
|
proxy_password=proxy_password,
|
|
600
|
+
certificates=_process_certificates(certificates),
|
|
544
601
|
experimental_features=experimental_features,
|
|
545
602
|
)
|
|
546
603
|
initial_response = self._submit_task(payload)
|
|
@@ -811,6 +868,7 @@ class SmoothAsyncClient(BaseClient):
|
|
|
811
868
|
proxy_server: str | None = None,
|
|
812
869
|
proxy_username: str | None = None,
|
|
813
870
|
proxy_password: str | None = None,
|
|
871
|
+
certificates: list[Certificate] | None = None,
|
|
814
872
|
experimental_features: dict[str, Any] | None = None,
|
|
815
873
|
) -> AsyncTaskHandle:
|
|
816
874
|
"""Runs a task and returns a handle to the task asynchronously.
|
|
@@ -837,6 +895,10 @@ class SmoothAsyncClient(BaseClient):
|
|
|
837
895
|
proxy_server: Proxy server url to route browser traffic through.
|
|
838
896
|
proxy_username: Proxy server username.
|
|
839
897
|
proxy_password: Proxy server password.
|
|
898
|
+
certificates: List of client certificates to use when accessing secure websites.
|
|
899
|
+
Each certificate is a dictionary with the following fields:
|
|
900
|
+
- `file` (required): p12 file object to be uploaded (e.g., open("cert.p12", "rb")).
|
|
901
|
+
- `password` (optional): Password to decrypt the certificate file.
|
|
840
902
|
experimental_features: Experimental features to enable for the task.
|
|
841
903
|
|
|
842
904
|
Returns:
|
|
@@ -862,6 +924,7 @@ class SmoothAsyncClient(BaseClient):
|
|
|
862
924
|
proxy_server=proxy_server,
|
|
863
925
|
proxy_username=proxy_username,
|
|
864
926
|
proxy_password=proxy_password,
|
|
927
|
+
certificates=_process_certificates(certificates),
|
|
865
928
|
experimental_features=experimental_features,
|
|
866
929
|
)
|
|
867
930
|
|
|
@@ -1000,6 +1063,7 @@ __all__ = [
|
|
|
1000
1063
|
"BrowserSessionResponse",
|
|
1001
1064
|
"BrowserSessionsResponse",
|
|
1002
1065
|
"UploadFileResponse",
|
|
1066
|
+
"Certificate",
|
|
1003
1067
|
"ApiError",
|
|
1004
1068
|
"TimeoutError",
|
|
1005
1069
|
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|