smooth-py 0.2.7.dev20251003__py3-none-any.whl → 0.2.8.dev20251006__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.

Potentially problematic release.


This version of smooth-py might be problematic. Click here for more details.

smooth/__init__.py CHANGED
@@ -13,7 +13,7 @@ from typing import Any, Literal, Type
13
13
  import httpx
14
14
  import requests
15
15
  from deprecated import deprecated
16
- from pydantic import BaseModel, Field, model_validator
16
+ from pydantic import BaseModel, ConfigDict, Field, model_validator
17
17
 
18
18
  # Configure logging
19
19
  logger = logging.getLogger("smooth")
@@ -39,8 +39,10 @@ def _encode_url(url: str, interactive: bool = True, embed: bool = False) -> str:
39
39
  class TaskResponse(BaseModel):
40
40
  """Task response model."""
41
41
 
42
+ model_config = ConfigDict(extra="allow")
43
+
42
44
  id: str = Field(description="The ID of the task.")
43
- status: Literal["waiting", "running", "done", "failed"] = Field(description="The status of the task.")
45
+ status: Literal["waiting", "running", "done", "failed", "cancelled"] = Field(description="The status of the task.")
44
46
  output: Any | None = Field(default=None, description="The output of the task.")
45
47
  credits_used: int | None = Field(default=None, description="The amount of credits used to perform the task.")
46
48
  device: Literal["desktop", "mobile"] | None = Field(default=None, description="The device type used for the task.")
@@ -89,7 +91,9 @@ class TaskRequest(BaseModel):
89
91
  )
90
92
  proxy_username: str | None = Field(default=None, description="Proxy server username.")
91
93
  proxy_password: str | None = Field(default=None, description="Proxy server password.")
92
- experimental_features: dict[str, Any] | None = Field(default=None, description="Experimental features to enable for the task.")
94
+ experimental_features: dict[str, Any] | None = Field(
95
+ default=None, description="Experimental features to enable for the task."
96
+ )
93
97
 
94
98
  @model_validator(mode="before")
95
99
  @classmethod
@@ -145,6 +149,7 @@ class BrowserSessionResponse(BaseModel):
145
149
  """Browser session response model."""
146
150
 
147
151
  profile_id: str = Field(description="The ID of the browser profile associated with the opened browser instance.")
152
+ live_id: str | None = Field(description="The ID of the live browser session.")
148
153
  live_url: str | None = Field(default=None, description="The live URL to interact with the browser session.")
149
154
 
150
155
  @model_validator(mode="before")
@@ -196,6 +201,7 @@ class BrowserProfilesResponse(BaseModel):
196
201
 
197
202
  class BrowserSessionsResponse(BrowserProfilesResponse):
198
203
  """Response model for listing browser profiles."""
204
+
199
205
  pass
200
206
 
201
207
 
@@ -309,6 +315,15 @@ class TaskHandle:
309
315
  """Returns the task ID."""
310
316
  return self._id
311
317
 
318
+ def stop(self):
319
+ """Stops the task."""
320
+ try:
321
+ response = self._client._client.delete(f"{self._client.base_url}/task/{self._id}")
322
+ self._handle_response(response)
323
+ except requests.exceptions.RequestException as e:
324
+ logger.error(f"Request failed: {e}")
325
+ raise ApiError(status_code=0, detail=f"Request failed: {str(e)}") from None
326
+
312
327
  def result(self, timeout: int | None = None, poll_interval: float = 1) -> TaskResponse:
313
328
  """Waits for the task to complete and returns the result."""
314
329
  if self._task_response and self._task_response.status not in ["running", "waiting"]:
@@ -417,11 +432,12 @@ class SmoothClient(BaseClient):
417
432
  enable_recording: bool = False,
418
433
  session_id: str | None = None,
419
434
  profile_id: str | None = None,
420
- profile_read_only: bool | None = None,
435
+ profile_read_only: bool = False,
421
436
  stealth_mode: bool = False,
422
437
  proxy_server: str | None = None,
423
438
  proxy_username: str | None = None,
424
439
  proxy_password: str | None = None,
440
+ experimental_features: dict[str, Any] | None = None,
425
441
  ) -> TaskHandle:
426
442
  """Runs a task and returns a handle to the task.
427
443
 
@@ -447,6 +463,7 @@ class SmoothClient(BaseClient):
447
463
  proxy_server: Proxy server url to route browser traffic through.
448
464
  proxy_username: Proxy server username.
449
465
  proxy_password: Proxy server password.
466
+ experimental_features: Experimental features to enable for the task.
450
467
 
451
468
  Returns:
452
469
  A handle to the running task.
@@ -471,6 +488,7 @@ class SmoothClient(BaseClient):
471
488
  proxy_server=proxy_server,
472
489
  proxy_username=proxy_username,
473
490
  proxy_password=proxy_password,
491
+ experimental_features=experimental_features,
474
492
  )
475
493
  initial_response = self._submit_task(payload)
476
494
 
@@ -503,6 +521,15 @@ class SmoothClient(BaseClient):
503
521
  logger.error(f"Request failed: {e}")
504
522
  raise ApiError(status_code=0, detail=f"Request failed: {str(e)}") from None
505
523
 
524
+ def close_session(self, live_id: str):
525
+ """Closes a browser session."""
526
+ try:
527
+ response = self._session.delete(f"{self.base_url}/browser/session/{live_id}")
528
+ self._handle_response(response)
529
+ except requests.exceptions.RequestException as e:
530
+ logger.error(f"Request failed: {e}")
531
+ raise ApiError(status_code=0, detail=f"Request failed: {str(e)}") from None
532
+
506
533
  def list_profiles(self):
507
534
  """Lists all browser profiles for the user.
508
535
 
@@ -702,11 +729,12 @@ class SmoothAsyncClient(BaseClient):
702
729
  enable_recording: bool = False,
703
730
  session_id: str | None = None,
704
731
  profile_id: str | None = None,
705
- profile_read_only: bool | None = None,
732
+ profile_read_only: bool = False,
706
733
  stealth_mode: bool = False,
707
734
  proxy_server: str | None = None,
708
735
  proxy_username: str | None = None,
709
736
  proxy_password: str | None = None,
737
+ experimental_features: dict[str, Any] | None = None,
710
738
  ) -> AsyncTaskHandle:
711
739
  """Runs a task and returns a handle to the task asynchronously.
712
740
 
@@ -732,8 +760,7 @@ class SmoothAsyncClient(BaseClient):
732
760
  proxy_server: Proxy server url to route browser traffic through.
733
761
  proxy_username: Proxy server username.
734
762
  proxy_password: Proxy server password.
735
- poll_interval: The time in seconds to wait between polling for status.
736
- timeout: The maximum time in seconds to wait for the task to complete.
763
+ experimental_features: Experimental features to enable for the task.
737
764
 
738
765
  Returns:
739
766
  A handle to the running task.
@@ -758,6 +785,7 @@ class SmoothAsyncClient(BaseClient):
758
785
  proxy_server=proxy_server,
759
786
  proxy_username=proxy_username,
760
787
  proxy_password=proxy_password,
788
+ experimental_features=experimental_features,
761
789
  )
762
790
 
763
791
  initial_response = await self._submit_task(payload)
@@ -790,6 +818,15 @@ class SmoothAsyncClient(BaseClient):
790
818
  logger.error(f"Request failed: {e}")
791
819
  raise ApiError(status_code=0, detail=f"Request failed: {str(e)}") from None
792
820
 
821
+ async def close_session(self, live_id: str):
822
+ """Closes a browser session."""
823
+ try:
824
+ response = await self._client.delete(f"{self.base_url}/browser/session/{live_id}")
825
+ self._handle_response(response)
826
+ except httpx.RequestError as e:
827
+ logger.error(f"Request failed: {e}")
828
+ raise ApiError(status_code=0, detail=f"Request failed: {str(e)}") from None
829
+
793
830
  async def list_profiles(self):
794
831
  """Lists all browser profiles for the user.
795
832
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: smooth-py
3
- Version: 0.2.7.dev20251003
3
+ Version: 0.2.8.dev20251006
4
4
  Summary:
5
5
  Author: Luca Pinchetti
6
6
  Author-email: luca@circlemind.co
@@ -0,0 +1,6 @@
1
+ smooth/__init__.py,sha256=xhuejYJ3ELuk_lZt9YqxYJwMwDAflSFYAyUrdMT2BK4,36348
2
+ smooth/mcp/__init__.py,sha256=0aJVFi2a8Ah3-5xtgyZ5UMbaaJsBWu2T8QLWoFQITk8,219
3
+ smooth/mcp/server.py,sha256=9SymTD4NOGTMN8P-LNGlvYNvv81yCIZfZeeuhEcAc6s,20068
4
+ smooth_py-0.2.8.dev20251006.dist-info/METADATA,sha256=jdsz_-QiHQVMbEp-9mz-RaURNEu0nkpGoW-LehMIKMA,7529
5
+ smooth_py-0.2.8.dev20251006.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
6
+ smooth_py-0.2.8.dev20251006.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- smooth/__init__.py,sha256=K87borOPyOmOeTzzwZnzEh0Ro8LxUO9swX1GWwjgd0Y,34860
2
- smooth/mcp/__init__.py,sha256=0aJVFi2a8Ah3-5xtgyZ5UMbaaJsBWu2T8QLWoFQITk8,219
3
- smooth/mcp/server.py,sha256=9SymTD4NOGTMN8P-LNGlvYNvv81yCIZfZeeuhEcAc6s,20068
4
- smooth_py-0.2.7.dev20251003.dist-info/METADATA,sha256=dXFh8dUH8CVnJ9hgE2x4x95nT1XRvIBB51GedlNs9po,7529
5
- smooth_py-0.2.7.dev20251003.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
6
- smooth_py-0.2.7.dev20251003.dist-info/RECORD,,