fleet-python 0.2.5__py3-none-any.whl → 0.2.7__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 fleet-python might be problematic. Click here for more details.
- examples/dsl_example.py +3 -0
- examples/example.py +4 -1
- examples/example_client.py +43 -0
- examples/example_sync.py +40 -0
- examples/json_tasks_example.py +3 -0
- examples/nova_act_example.py +3 -0
- examples/openai_example.py +3 -0
- examples/openai_simple_example.py +3 -0
- examples/quickstart.py +30 -48
- fleet/__init__.py +1 -1
- fleet/_async/__init__.py +1 -0
- fleet/_async/client.py +7 -3
- fleet/_async/env/client.py +6 -2
- fleet/_async/instance/client.py +16 -118
- fleet/_async/playwright.py +2 -2
- fleet/client.py +7 -3
- fleet/env/client.py +6 -2
- fleet/instance/__init__.py +1 -3
- fleet/instance/client.py +15 -118
- fleet/playwright.py +9 -8
- {fleet_python-0.2.5.dist-info → fleet_python-0.2.7.dist-info}/METADATA +43 -1
- {fleet_python-0.2.5.dist-info → fleet_python-0.2.7.dist-info}/RECORD +26 -22
- scripts/fix_sync_imports.py +69 -0
- {fleet_python-0.2.5.dist-info → fleet_python-0.2.7.dist-info}/WHEEL +0 -0
- {fleet_python-0.2.5.dist-info → fleet_python-0.2.7.dist-info}/licenses/LICENSE +0 -0
- {fleet_python-0.2.5.dist-info → fleet_python-0.2.7.dist-info}/top_level.txt +0 -0
examples/dsl_example.py
CHANGED
examples/example.py
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
import asyncio
|
|
5
5
|
import fleet as flt
|
|
6
|
+
from dotenv import load_dotenv
|
|
7
|
+
|
|
8
|
+
load_dotenv()
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
async def main():
|
|
@@ -11,7 +14,7 @@ async def main():
|
|
|
11
14
|
|
|
12
15
|
# Create a new instance
|
|
13
16
|
env = await flt.env.make_async("hubspot:v1.2.7")
|
|
14
|
-
print("New Instance:
|
|
17
|
+
print(f"New Instance: {env.instance_id} ({env.region})")
|
|
15
18
|
|
|
16
19
|
response = await env.reset(seed=42)
|
|
17
20
|
print("Reset response:", response)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Example demonstrating browser control with Fleet Manager Client."""
|
|
3
|
+
|
|
4
|
+
import asyncio
|
|
5
|
+
import fleet as flt
|
|
6
|
+
from dotenv import load_dotenv
|
|
7
|
+
|
|
8
|
+
load_dotenv()
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def main():
|
|
12
|
+
fleet = flt.AsyncFleet()
|
|
13
|
+
|
|
14
|
+
environments = await fleet.list_envs()
|
|
15
|
+
print("Environments:", len(environments))
|
|
16
|
+
|
|
17
|
+
# Create a new instance
|
|
18
|
+
env = await fleet.make("fira")
|
|
19
|
+
print(f"New Instance: {env.instance_id} ({env.region})")
|
|
20
|
+
|
|
21
|
+
response = await env.reset(seed=42)
|
|
22
|
+
print("Reset response:", response)
|
|
23
|
+
|
|
24
|
+
print(await env.resources())
|
|
25
|
+
|
|
26
|
+
sqlite = env.db()
|
|
27
|
+
print("SQLite:", await sqlite.describe())
|
|
28
|
+
|
|
29
|
+
print("Query:", await sqlite.query("SELECT * FROM users"))
|
|
30
|
+
|
|
31
|
+
sqlite = await env.state("sqlite://current").describe()
|
|
32
|
+
print("SQLite:", sqlite)
|
|
33
|
+
|
|
34
|
+
browser = env.browser()
|
|
35
|
+
print("CDP URL:", await browser.cdp_url())
|
|
36
|
+
print("Devtools URL:", await browser.devtools_url())
|
|
37
|
+
|
|
38
|
+
# Delete the instance
|
|
39
|
+
await fleet.delete(env.instance_id)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
if __name__ == "__main__":
|
|
43
|
+
asyncio.run(main())
|
examples/example_sync.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Example demonstrating browser control with Fleet Manager Client."""
|
|
3
|
+
|
|
4
|
+
import fleet as flt
|
|
5
|
+
from dotenv import load_dotenv
|
|
6
|
+
|
|
7
|
+
load_dotenv()
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main():
|
|
11
|
+
environments = flt.env.list_envs()
|
|
12
|
+
print("Environments:", len(environments))
|
|
13
|
+
|
|
14
|
+
# Create a new instance
|
|
15
|
+
env = flt.env.make("hubspot:v1.2.7")
|
|
16
|
+
print("New Instance:", env.instance_id)
|
|
17
|
+
|
|
18
|
+
response = env.reset(seed=42)
|
|
19
|
+
print("Reset response:", response)
|
|
20
|
+
|
|
21
|
+
print(env.resources())
|
|
22
|
+
|
|
23
|
+
sqlite = env.db()
|
|
24
|
+
print("SQLite:", sqlite.describe())
|
|
25
|
+
|
|
26
|
+
print("Query:", sqlite.query("SELECT * FROM users"))
|
|
27
|
+
|
|
28
|
+
sqlite = env.state("sqlite://current").describe()
|
|
29
|
+
print("SQLite:", sqlite)
|
|
30
|
+
|
|
31
|
+
browser = env.browser()
|
|
32
|
+
print("CDP URL:", browser.cdp_url())
|
|
33
|
+
print("Devtools URL:", browser.devtools_url())
|
|
34
|
+
|
|
35
|
+
# Delete the instance
|
|
36
|
+
env.close()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
if __name__ == "__main__":
|
|
40
|
+
main()
|
examples/json_tasks_example.py
CHANGED
examples/nova_act_example.py
CHANGED
examples/openai_example.py
CHANGED
examples/quickstart.py
CHANGED
|
@@ -7,9 +7,11 @@ This example demonstrates basic usage of the Fleet SDK for environment managemen
|
|
|
7
7
|
|
|
8
8
|
import asyncio
|
|
9
9
|
import logging
|
|
10
|
-
from
|
|
10
|
+
from dotenv import load_dotenv
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
load_dotenv()
|
|
13
|
+
|
|
14
|
+
from fleet import AsyncFleet
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
# Configure logging
|
|
@@ -19,23 +21,14 @@ logger = logging.getLogger(__name__)
|
|
|
19
21
|
|
|
20
22
|
async def main():
|
|
21
23
|
"""Main example function."""
|
|
22
|
-
|
|
23
|
-
#
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
config = fleet.get_config()
|
|
27
|
-
client = fleet.FleetAPIClient(config)
|
|
28
|
-
health = await client.health_check()
|
|
29
|
-
print(f"✅ API Status: {health.status}")
|
|
30
|
-
await client.close()
|
|
31
|
-
except Exception as e:
|
|
32
|
-
print(f"❌ API Health Check failed: {e}")
|
|
33
|
-
return
|
|
34
|
-
|
|
24
|
+
|
|
25
|
+
# Initialize the Fleet client
|
|
26
|
+
fleet_client = AsyncFleet()
|
|
27
|
+
|
|
35
28
|
# 1. List available environments
|
|
36
29
|
print("\n📋 Available environments:")
|
|
37
30
|
try:
|
|
38
|
-
environments = await
|
|
31
|
+
environments = await fleet_client.list_envs()
|
|
39
32
|
for env in environments:
|
|
40
33
|
print(f" - {env.env_key}: {env.name}")
|
|
41
34
|
print(f" Description: {env.description}")
|
|
@@ -44,77 +37,66 @@ async def main():
|
|
|
44
37
|
except Exception as e:
|
|
45
38
|
print(f"❌ Failed to list environments: {e}")
|
|
46
39
|
return
|
|
47
|
-
|
|
40
|
+
|
|
48
41
|
# 2. Create a new environment instance
|
|
49
42
|
print("\n🚀 Creating new environment...")
|
|
50
43
|
try:
|
|
51
|
-
env = await
|
|
44
|
+
env = await fleet_client.make("fira:v1.3.1")
|
|
52
45
|
print(f"✅ Environment created with instance ID: {env.instance_id}")
|
|
53
|
-
|
|
54
|
-
# Execute a simple action
|
|
46
|
+
|
|
47
|
+
# TODO: Execute a simple action
|
|
55
48
|
print("\n⚡ Executing a simple action...")
|
|
56
49
|
action = {"type": "test", "data": {"message": "Hello Fleet!"}}
|
|
57
|
-
state, reward, done = await env.step(action)
|
|
50
|
+
state, reward, done = await env.instance.step(action)
|
|
58
51
|
print(f"✅ Action executed successfully!")
|
|
59
52
|
print(f" Reward: {reward}")
|
|
60
53
|
print(f" Done: {done}")
|
|
61
54
|
print(f" State keys: {list(state.keys())}")
|
|
62
|
-
|
|
63
|
-
# Check manager API health
|
|
64
|
-
print("\n🏥 Checking manager API health...")
|
|
65
|
-
try:
|
|
66
|
-
manager_health = await env.manager_health_check()
|
|
67
|
-
if manager_health:
|
|
68
|
-
print(f"✅ Manager API Status: {manager_health.status}")
|
|
69
|
-
print(f" Service: {manager_health.service}")
|
|
70
|
-
print(f" Timestamp: {manager_health.timestamp}")
|
|
71
|
-
else:
|
|
72
|
-
print("❌ Manager API not available")
|
|
73
|
-
except Exception as e:
|
|
74
|
-
print(f"❌ Manager health check failed: {e}")
|
|
75
|
-
|
|
55
|
+
|
|
76
56
|
# Clean up
|
|
77
57
|
print("\n🧹 Cleaning up...")
|
|
78
58
|
await env.close()
|
|
79
59
|
print("✅ Environment closed")
|
|
80
|
-
|
|
60
|
+
|
|
81
61
|
except Exception as e:
|
|
82
62
|
print(f"❌ Environment creation failed: {e}")
|
|
83
63
|
return
|
|
84
|
-
|
|
64
|
+
|
|
85
65
|
# 3. List running instances
|
|
86
66
|
print("\n🏃 Listing running instances...")
|
|
87
67
|
try:
|
|
88
|
-
instances = await
|
|
68
|
+
instances = await fleet_client.instances(status="running")
|
|
89
69
|
if instances:
|
|
90
70
|
print(f"Found {len(instances)} running instances:")
|
|
91
71
|
for instance in instances:
|
|
92
|
-
print(
|
|
72
|
+
print(
|
|
73
|
+
f" - {instance.instance_id}: {instance.env_key} ({instance.status})"
|
|
74
|
+
)
|
|
93
75
|
else:
|
|
94
76
|
print("No running instances found")
|
|
95
77
|
except Exception as e:
|
|
96
78
|
print(f"❌ Failed to list instances: {e}")
|
|
97
|
-
|
|
79
|
+
|
|
98
80
|
# 4. Connect to an existing instance (if any)
|
|
99
81
|
print("\n🔗 Connecting to existing instance...")
|
|
100
82
|
try:
|
|
101
83
|
# Only get running instances
|
|
102
|
-
running_instances = await
|
|
84
|
+
running_instances = await fleet_client.instances(status="running")
|
|
103
85
|
if running_instances:
|
|
104
86
|
# Find a running instance that's not the one we just created/deleted
|
|
105
87
|
target_instance = running_instances[0]
|
|
106
88
|
print(f"Connecting to running instance: {target_instance.instance_id}")
|
|
107
|
-
|
|
108
|
-
env = await
|
|
89
|
+
|
|
90
|
+
env = await fleet_client.instance(target_instance.instance_id)
|
|
109
91
|
print(f"✅ Connected to instance: {env.instance_id}")
|
|
110
|
-
|
|
92
|
+
|
|
111
93
|
# Execute an action on the existing instance
|
|
112
94
|
action = {"type": "ping", "data": {"timestamp": "2024-01-01T00:00:00Z"}}
|
|
113
|
-
state, reward, done = await env.step(action)
|
|
95
|
+
state, reward, done = await env.instance.step(action)
|
|
114
96
|
print(f"✅ Action executed on existing instance!")
|
|
115
97
|
print(f" Reward: {reward}")
|
|
116
98
|
print(f" Done: {done}")
|
|
117
|
-
|
|
99
|
+
|
|
118
100
|
# Clean up (this will delete the instance)
|
|
119
101
|
await env.close()
|
|
120
102
|
print("✅ Connection closed (instance deleted)")
|
|
@@ -122,9 +104,9 @@ async def main():
|
|
|
122
104
|
print("No running instances to connect to")
|
|
123
105
|
except Exception as e:
|
|
124
106
|
print(f"❌ Failed to connect to existing instance: {e}")
|
|
125
|
-
|
|
107
|
+
|
|
126
108
|
print("\n🎉 Quickstart complete!")
|
|
127
109
|
|
|
128
110
|
|
|
129
111
|
if __name__ == "__main__":
|
|
130
|
-
asyncio.run(main())
|
|
112
|
+
asyncio.run(main())
|
fleet/__init__.py
CHANGED
|
@@ -25,7 +25,6 @@ from ._async.client import AsyncFleet, AsyncEnvironment
|
|
|
25
25
|
from .models import InstanceRequest
|
|
26
26
|
from .instance import (
|
|
27
27
|
InstanceClient,
|
|
28
|
-
AsyncInstanceClient,
|
|
29
28
|
ResetRequest,
|
|
30
29
|
ResetResponse,
|
|
31
30
|
CDPDescribeResponse,
|
|
@@ -33,6 +32,7 @@ from .instance import (
|
|
|
33
32
|
ChromeStartResponse,
|
|
34
33
|
ChromeStatusResponse,
|
|
35
34
|
)
|
|
35
|
+
from ._async.instance import AsyncInstanceClient
|
|
36
36
|
from .verifiers import (
|
|
37
37
|
DatabaseSnapshot,
|
|
38
38
|
IgnoreConfig,
|
fleet/_async/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# This file makes the _async directory a proper Python package
|
fleet/_async/client.py
CHANGED
|
@@ -126,8 +126,12 @@ class AsyncFleet:
|
|
|
126
126
|
|
|
127
127
|
async def instance(self, instance_id: str) -> AsyncEnvironment:
|
|
128
128
|
response = await self.client.request("GET", f"/v1/env/instances/{instance_id}")
|
|
129
|
-
|
|
129
|
+
instance = AsyncEnvironment(**response.json())
|
|
130
|
+
await instance.instance.load()
|
|
131
|
+
return instance
|
|
130
132
|
|
|
131
133
|
async def delete(self, instance_id: str) -> InstanceRecord:
|
|
132
|
-
response = await self.client.request(
|
|
133
|
-
|
|
134
|
+
response = await self.client.request(
|
|
135
|
+
"DELETE", f"/v1/env/instances/{instance_id}"
|
|
136
|
+
)
|
|
137
|
+
return InstanceRecord(**response.json())
|
fleet/_async/env/client.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from ..client import AsyncFleet, AsyncEnvironment
|
|
2
2
|
from ..models import Environment as EnvironmentModel
|
|
3
|
-
from typing import List
|
|
3
|
+
from typing import List, Optional
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
async def make_async(env_key: str) -> AsyncEnvironment:
|
|
@@ -11,5 +11,9 @@ async def list_envs_async() -> List[EnvironmentModel]:
|
|
|
11
11
|
return await AsyncFleet().list_envs()
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
async def list_instances_async(status: Optional[str] = None) -> List[AsyncEnvironment]:
|
|
15
|
+
return await AsyncFleet().instances(status=status)
|
|
16
|
+
|
|
17
|
+
|
|
14
18
|
async def get_async(instance_id: str) -> AsyncEnvironment:
|
|
15
|
-
return await AsyncFleet().instance(instance_id)
|
|
19
|
+
return await AsyncFleet().instance(instance_id)
|
fleet/_async/instance/client.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Fleet SDK
|
|
1
|
+
"""Fleet SDK Instance Client."""
|
|
2
2
|
|
|
3
3
|
from typing import Any, Callable, Dict, List, Optional, Tuple
|
|
4
4
|
import asyncio
|
|
@@ -12,7 +12,7 @@ from ..resources.sqlite import AsyncSQLiteResource
|
|
|
12
12
|
from ..resources.browser import AsyncBrowserResource
|
|
13
13
|
from ..resources.base import Resource
|
|
14
14
|
|
|
15
|
-
from
|
|
15
|
+
from fleet.verifiers import DatabaseSnapshot
|
|
16
16
|
|
|
17
17
|
from ..exceptions import FleetEnvironmentError, FleetAPIError
|
|
18
18
|
|
|
@@ -75,13 +75,13 @@ class AsyncInstanceClient:
|
|
|
75
75
|
|
|
76
76
|
def db(self, name: str) -> AsyncSQLiteResource:
|
|
77
77
|
"""
|
|
78
|
-
Returns an
|
|
78
|
+
Returns an SQLite database resource for the given database name.
|
|
79
79
|
|
|
80
80
|
Args:
|
|
81
81
|
name: The name of the SQLite database to return
|
|
82
82
|
|
|
83
83
|
Returns:
|
|
84
|
-
An
|
|
84
|
+
An SQLite database resource for the given database name
|
|
85
85
|
"""
|
|
86
86
|
return AsyncSQLiteResource(
|
|
87
87
|
self._resources_state[ResourceType.db.value][name], self.client
|
|
@@ -144,135 +144,33 @@ class AsyncInstanceClient:
|
|
|
144
144
|
|
|
145
145
|
async def step(self, action: Dict[str, Any]) -> Tuple[Dict[str, Any], float, bool]:
|
|
146
146
|
"""Execute one step in the environment."""
|
|
147
|
-
if not self._instance_id:
|
|
148
|
-
raise FleetEnvironmentError(
|
|
149
|
-
"Environment not initialized. Call reset() first."
|
|
150
|
-
)
|
|
151
|
-
|
|
152
147
|
try:
|
|
153
|
-
#
|
|
154
|
-
|
|
148
|
+
# Create a placeholder state
|
|
149
|
+
state = {
|
|
150
|
+
"action": action,
|
|
151
|
+
"timestamp": time.time(),
|
|
152
|
+
"status": "completed",
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
# Create a placeholder reward
|
|
156
|
+
reward = 0.0
|
|
155
157
|
|
|
156
|
-
#
|
|
157
|
-
|
|
158
|
-
state, reward, done = await self._execute_action(action)
|
|
158
|
+
# Determine if episode is done (placeholder logic)
|
|
159
|
+
done = False
|
|
159
160
|
|
|
160
161
|
return state, reward, done
|
|
161
162
|
|
|
162
163
|
except Exception as e:
|
|
163
164
|
raise FleetEnvironmentError(f"Failed to execute step: {e}")
|
|
164
165
|
|
|
165
|
-
async def close(self) -> None:
|
|
166
|
-
"""Close the environment and clean up resources."""
|
|
167
|
-
try:
|
|
168
|
-
# Delete instance if it exists
|
|
169
|
-
if self._instance_id:
|
|
170
|
-
try:
|
|
171
|
-
await self._client.delete_instance(self._instance_id)
|
|
172
|
-
logger.info(f"Deleted instance: {self._instance_id}")
|
|
173
|
-
except FleetAPIError as e:
|
|
174
|
-
logger.warning(f"Failed to delete instance: {e}")
|
|
175
|
-
finally:
|
|
176
|
-
self._instance_id = None
|
|
177
|
-
self._instance_response = None
|
|
178
|
-
|
|
179
|
-
# Close manager client
|
|
180
|
-
if self._manager_client:
|
|
181
|
-
await self._manager_client.close()
|
|
182
|
-
self._manager_client = None
|
|
183
|
-
|
|
184
|
-
# Close API client
|
|
185
|
-
await self._client.close()
|
|
186
|
-
|
|
187
|
-
except Exception as e:
|
|
188
|
-
logger.error(f"Error closing environment: {e}")
|
|
189
|
-
|
|
190
166
|
async def manager_health_check(self) -> Optional[HealthResponse]:
|
|
191
167
|
response = await self.client.request("GET", "/health")
|
|
192
168
|
return HealthResponse(**response.json())
|
|
193
169
|
|
|
194
|
-
async def _wait_for_instance_ready(self, timeout: float = 300.0) -> None:
|
|
195
|
-
"""Wait for instance to be ready.
|
|
196
|
-
|
|
197
|
-
Args:
|
|
198
|
-
timeout: Maximum time to wait in seconds
|
|
199
|
-
"""
|
|
200
|
-
start_time = time.time()
|
|
201
|
-
|
|
202
|
-
while time.time() - start_time < timeout:
|
|
203
|
-
try:
|
|
204
|
-
instance = await self._client.get_instance(self._instance_id)
|
|
205
|
-
self._instance_response = instance
|
|
206
|
-
|
|
207
|
-
if instance.status == "running":
|
|
208
|
-
logger.info(f"Instance {self._instance_id} is ready")
|
|
209
|
-
return
|
|
210
|
-
|
|
211
|
-
elif instance.status == "error":
|
|
212
|
-
raise FleetEnvironmentError(
|
|
213
|
-
f"Instance {self._instance_id} failed to start"
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
# Wait before checking again
|
|
217
|
-
await asyncio.sleep(5)
|
|
218
|
-
|
|
219
|
-
except FleetAPIError as e:
|
|
220
|
-
if time.time() - start_time >= timeout:
|
|
221
|
-
raise FleetEnvironmentError(
|
|
222
|
-
f"Timeout waiting for instance to be ready: {e}"
|
|
223
|
-
)
|
|
224
|
-
await asyncio.sleep(5)
|
|
225
|
-
|
|
226
|
-
raise FleetEnvironmentError(
|
|
227
|
-
f"Timeout waiting for instance {self._instance_id} to be ready"
|
|
228
|
-
)
|
|
229
|
-
|
|
230
|
-
async def _execute_action(
|
|
231
|
-
self, action: Dict[str, Any]
|
|
232
|
-
) -> Tuple[Dict[str, Any], float, bool]:
|
|
233
|
-
"""Execute an action through the instance manager API.
|
|
234
|
-
|
|
235
|
-
This is a placeholder implementation that should be extended based on
|
|
236
|
-
the actual manager API specification.
|
|
237
|
-
|
|
238
|
-
Args:
|
|
239
|
-
action: The action to execute as a dictionary
|
|
240
|
-
|
|
241
|
-
Returns:
|
|
242
|
-
Tuple of (state, reward, done)
|
|
243
|
-
"""
|
|
244
|
-
# Ensure manager client is available
|
|
245
|
-
await self._ensure_manager_client()
|
|
246
|
-
|
|
247
|
-
# TODO: In the future, this would use the manager API to execute actions
|
|
248
|
-
# For example: await self._manager_client.log_action(action)
|
|
249
|
-
# For now, return placeholder values
|
|
250
|
-
|
|
251
|
-
# Create a placeholder state
|
|
252
|
-
state = self._create_state_from_action(action)
|
|
253
|
-
|
|
254
|
-
# Create a placeholder reward
|
|
255
|
-
reward = 0.0
|
|
256
|
-
|
|
257
|
-
# Determine if episode is done (placeholder logic)
|
|
258
|
-
done = self._step_count >= 100 # Example: done after 100 steps
|
|
259
|
-
|
|
260
|
-
return state, reward, done
|
|
261
|
-
|
|
262
|
-
def _create_state_from_action(self, action: Dict[str, Any]) -> Dict[str, Any]:
|
|
263
|
-
"""Create state based on executed action."""
|
|
264
|
-
return {
|
|
265
|
-
"instance_id": self._instance_id,
|
|
266
|
-
"step": self._step_count,
|
|
267
|
-
"last_action": action,
|
|
268
|
-
"timestamp": time.time(),
|
|
269
|
-
"status": "running",
|
|
270
|
-
}
|
|
271
|
-
|
|
272
170
|
async def __aenter__(self):
|
|
273
171
|
"""Async context manager entry."""
|
|
274
172
|
return self
|
|
275
173
|
|
|
276
174
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
277
175
|
"""Async context manager exit."""
|
|
278
|
-
await self.close()
|
|
176
|
+
await self.close()
|
fleet/_async/playwright.py
CHANGED
|
@@ -34,7 +34,7 @@ CUA_KEY_TO_PLAYWRIGHT_KEY = {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
class
|
|
37
|
+
class AsyncFleetPlaywrightWrapper:
|
|
38
38
|
"""
|
|
39
39
|
A wrapper that adds Playwright browser automation to Fleet environment instances.
|
|
40
40
|
|
|
@@ -46,7 +46,7 @@ class FleetPlaywrightWrapper:
|
|
|
46
46
|
|
|
47
47
|
Usage:
|
|
48
48
|
instance = await fleet.env.make(env_key="hubspot", version="v1.2.7")
|
|
49
|
-
browser =
|
|
49
|
+
browser = AsyncFleetPlaywrightWrapper(instance)
|
|
50
50
|
await browser.start()
|
|
51
51
|
|
|
52
52
|
# Use browser methods
|
fleet/client.py
CHANGED
|
@@ -126,8 +126,12 @@ class Fleet:
|
|
|
126
126
|
|
|
127
127
|
def instance(self, instance_id: str) -> Environment:
|
|
128
128
|
response = self.client.request("GET", f"/v1/env/instances/{instance_id}")
|
|
129
|
-
|
|
129
|
+
instance = Environment(**response.json())
|
|
130
|
+
instance.instance.load()
|
|
131
|
+
return instance
|
|
130
132
|
|
|
131
133
|
def delete(self, instance_id: str) -> InstanceRecord:
|
|
132
|
-
response = self.client.request(
|
|
133
|
-
|
|
134
|
+
response = self.client.request(
|
|
135
|
+
"DELETE", f"/v1/env/instances/{instance_id}"
|
|
136
|
+
)
|
|
137
|
+
return InstanceRecord(**response.json())
|
fleet/env/client.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from ..client import Fleet, Environment
|
|
2
2
|
from ..models import Environment as EnvironmentModel
|
|
3
|
-
from typing import List
|
|
3
|
+
from typing import List, Optional
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def make(env_key: str) -> Environment:
|
|
@@ -11,5 +11,9 @@ def list_envs() -> List[EnvironmentModel]:
|
|
|
11
11
|
return Fleet().list_envs()
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
def list_instances(status: Optional[str] = None) -> List[Environment]:
|
|
15
|
+
return Fleet().instances(status=status)
|
|
16
|
+
|
|
17
|
+
|
|
14
18
|
def get(instance_id: str) -> Environment:
|
|
15
|
-
return Fleet().instance(instance_id)
|
|
19
|
+
return Fleet().instance(instance_id)
|
fleet/instance/__init__.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Fleet SDK Environment Module."""
|
|
2
2
|
|
|
3
3
|
from .client import InstanceClient, ValidatorType
|
|
4
|
-
from .._async.instance.client import AsyncInstanceClient
|
|
5
4
|
from .models import (
|
|
6
5
|
ResetRequest,
|
|
7
6
|
ResetResponse,
|
|
@@ -15,7 +14,6 @@ from .models import (
|
|
|
15
14
|
__all__ = [
|
|
16
15
|
"ValidatorType",
|
|
17
16
|
"InstanceClient",
|
|
18
|
-
"AsyncInstanceClient",
|
|
19
17
|
"ResetRequest",
|
|
20
18
|
"ResetResponse",
|
|
21
19
|
"CDPDescribeResponse",
|
|
@@ -23,4 +21,4 @@ __all__ = [
|
|
|
23
21
|
"ChromeStartResponse",
|
|
24
22
|
"ChromeStatusResponse",
|
|
25
23
|
"ExecuteFunctionResponse"
|
|
26
|
-
]
|
|
24
|
+
]
|
fleet/instance/client.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
"""Fleet SDK
|
|
1
|
+
"""Fleet SDK Instance Client."""
|
|
2
2
|
|
|
3
3
|
from typing import Any, Callable, Dict, List, Optional, Tuple
|
|
4
|
-
import asyncio
|
|
5
4
|
import httpx
|
|
6
5
|
import inspect
|
|
7
6
|
import time
|
|
@@ -75,13 +74,13 @@ class InstanceClient:
|
|
|
75
74
|
|
|
76
75
|
def db(self, name: str) -> SQLiteResource:
|
|
77
76
|
"""
|
|
78
|
-
Returns an
|
|
77
|
+
Returns an SQLite database resource for the given database name.
|
|
79
78
|
|
|
80
79
|
Args:
|
|
81
80
|
name: The name of the SQLite database to return
|
|
82
81
|
|
|
83
82
|
Returns:
|
|
84
|
-
An
|
|
83
|
+
An SQLite database resource for the given database name
|
|
85
84
|
"""
|
|
86
85
|
return SQLiteResource(
|
|
87
86
|
self._resources_state[ResourceType.db.value][name], self.client
|
|
@@ -144,135 +143,33 @@ class InstanceClient:
|
|
|
144
143
|
|
|
145
144
|
def step(self, action: Dict[str, Any]) -> Tuple[Dict[str, Any], float, bool]:
|
|
146
145
|
"""Execute one step in the environment."""
|
|
147
|
-
if not self._instance_id:
|
|
148
|
-
raise FleetEnvironmentError(
|
|
149
|
-
"Environment not initialized. Call reset() first."
|
|
150
|
-
)
|
|
151
|
-
|
|
152
146
|
try:
|
|
153
|
-
#
|
|
154
|
-
|
|
147
|
+
# Create a placeholder state
|
|
148
|
+
state = {
|
|
149
|
+
"action": action,
|
|
150
|
+
"timestamp": time.time(),
|
|
151
|
+
"status": "completed",
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
# Create a placeholder reward
|
|
155
|
+
reward = 0.0
|
|
155
156
|
|
|
156
|
-
#
|
|
157
|
-
|
|
158
|
-
state, reward, done = self._execute_action(action)
|
|
157
|
+
# Determine if episode is done (placeholder logic)
|
|
158
|
+
done = False
|
|
159
159
|
|
|
160
160
|
return state, reward, done
|
|
161
161
|
|
|
162
162
|
except Exception as e:
|
|
163
163
|
raise FleetEnvironmentError(f"Failed to execute step: {e}")
|
|
164
164
|
|
|
165
|
-
def close(self) -> None:
|
|
166
|
-
"""Close the environment and clean up resources."""
|
|
167
|
-
try:
|
|
168
|
-
# Delete instance if it exists
|
|
169
|
-
if self._instance_id:
|
|
170
|
-
try:
|
|
171
|
-
self._client.delete_instance(self._instance_id)
|
|
172
|
-
logger.info(f"Deleted instance: {self._instance_id}")
|
|
173
|
-
except FleetAPIError as e:
|
|
174
|
-
logger.warning(f"Failed to delete instance: {e}")
|
|
175
|
-
finally:
|
|
176
|
-
self._instance_id = None
|
|
177
|
-
self._instance_response = None
|
|
178
|
-
|
|
179
|
-
# Close manager client
|
|
180
|
-
if self._manager_client:
|
|
181
|
-
self._manager_client.close()
|
|
182
|
-
self._manager_client = None
|
|
183
|
-
|
|
184
|
-
# Close API client
|
|
185
|
-
self._client.close()
|
|
186
|
-
|
|
187
|
-
except Exception as e:
|
|
188
|
-
logger.error(f"Error closing environment: {e}")
|
|
189
|
-
|
|
190
165
|
def manager_health_check(self) -> Optional[HealthResponse]:
|
|
191
166
|
response = self.client.request("GET", "/health")
|
|
192
167
|
return HealthResponse(**response.json())
|
|
193
168
|
|
|
194
|
-
def _wait_for_instance_ready(self, timeout: float = 300.0) -> None:
|
|
195
|
-
"""Wait for instance to be ready.
|
|
196
|
-
|
|
197
|
-
Args:
|
|
198
|
-
timeout: Maximum time to wait in seconds
|
|
199
|
-
"""
|
|
200
|
-
start_time = time.time()
|
|
201
|
-
|
|
202
|
-
while time.time() - start_time < timeout:
|
|
203
|
-
try:
|
|
204
|
-
instance = self._client.get_instance(self._instance_id)
|
|
205
|
-
self._instance_response = instance
|
|
206
|
-
|
|
207
|
-
if instance.status == "running":
|
|
208
|
-
logger.info(f"Instance {self._instance_id} is ready")
|
|
209
|
-
return
|
|
210
|
-
|
|
211
|
-
elif instance.status == "error":
|
|
212
|
-
raise FleetEnvironmentError(
|
|
213
|
-
f"Instance {self._instance_id} failed to start"
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
# Wait before checking again
|
|
217
|
-
asyncio.sleep(5)
|
|
218
|
-
|
|
219
|
-
except FleetAPIError as e:
|
|
220
|
-
if time.time() - start_time >= timeout:
|
|
221
|
-
raise FleetEnvironmentError(
|
|
222
|
-
f"Timeout waiting for instance to be ready: {e}"
|
|
223
|
-
)
|
|
224
|
-
asyncio.sleep(5)
|
|
225
|
-
|
|
226
|
-
raise FleetEnvironmentError(
|
|
227
|
-
f"Timeout waiting for instance {self._instance_id} to be ready"
|
|
228
|
-
)
|
|
229
|
-
|
|
230
|
-
def _execute_action(
|
|
231
|
-
self, action: Dict[str, Any]
|
|
232
|
-
) -> Tuple[Dict[str, Any], float, bool]:
|
|
233
|
-
"""Execute an action through the instance manager API.
|
|
234
|
-
|
|
235
|
-
This is a placeholder implementation that should be extended based on
|
|
236
|
-
the actual manager API specification.
|
|
237
|
-
|
|
238
|
-
Args:
|
|
239
|
-
action: The action to execute as a dictionary
|
|
240
|
-
|
|
241
|
-
Returns:
|
|
242
|
-
Tuple of (state, reward, done)
|
|
243
|
-
"""
|
|
244
|
-
# Ensure manager client is available
|
|
245
|
-
self._ensure_manager_client()
|
|
246
|
-
|
|
247
|
-
# TODO: In the future, this would use the manager API to execute actions
|
|
248
|
-
# For example: await self._manager_client.log_action(action)
|
|
249
|
-
# For now, return placeholder values
|
|
250
|
-
|
|
251
|
-
# Create a placeholder state
|
|
252
|
-
state = self._create_state_from_action(action)
|
|
253
|
-
|
|
254
|
-
# Create a placeholder reward
|
|
255
|
-
reward = 0.0
|
|
256
|
-
|
|
257
|
-
# Determine if episode is done (placeholder logic)
|
|
258
|
-
done = self._step_count >= 100 # Example: done after 100 steps
|
|
259
|
-
|
|
260
|
-
return state, reward, done
|
|
261
|
-
|
|
262
|
-
def _create_state_from_action(self, action: Dict[str, Any]) -> Dict[str, Any]:
|
|
263
|
-
"""Create state based on executed action."""
|
|
264
|
-
return {
|
|
265
|
-
"instance_id": self._instance_id,
|
|
266
|
-
"step": self._step_count,
|
|
267
|
-
"last_action": action,
|
|
268
|
-
"timestamp": time.time(),
|
|
269
|
-
"status": "running",
|
|
270
|
-
}
|
|
271
|
-
|
|
272
169
|
def __enter__(self):
|
|
273
170
|
"""Async context manager entry."""
|
|
274
171
|
return self
|
|
275
172
|
|
|
276
173
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
277
174
|
"""Async context manager exit."""
|
|
278
|
-
self.close()
|
|
175
|
+
self.close()
|
fleet/playwright.py
CHANGED
|
@@ -45,16 +45,16 @@ class FleetPlaywrightWrapper:
|
|
|
45
45
|
- Integration with OpenAI computer use API
|
|
46
46
|
|
|
47
47
|
Usage:
|
|
48
|
-
instance =
|
|
48
|
+
instance = fleet.env.make(env_key="hubspot", version="v1.2.7")
|
|
49
49
|
browser = FleetPlaywrightWrapper(instance)
|
|
50
|
-
|
|
50
|
+
browser.start()
|
|
51
51
|
|
|
52
52
|
# Use browser methods
|
|
53
|
-
screenshot =
|
|
53
|
+
screenshot = browser.screenshot()
|
|
54
54
|
tools = [browser.openai_cua_tool]
|
|
55
55
|
|
|
56
56
|
# Clean up when done
|
|
57
|
-
|
|
57
|
+
browser.close()
|
|
58
58
|
"""
|
|
59
59
|
|
|
60
60
|
def get_environment(self):
|
|
@@ -100,7 +100,9 @@ class FleetPlaywrightWrapper:
|
|
|
100
100
|
cdp = self.env.browser().describe()
|
|
101
101
|
|
|
102
102
|
# Connect to browser
|
|
103
|
-
self._browser = self._playwright.chromium.connect_over_cdp(
|
|
103
|
+
self._browser = self._playwright.chromium.connect_over_cdp(
|
|
104
|
+
cdp.cdp_browser_url
|
|
105
|
+
)
|
|
104
106
|
self._page = self._browser.contexts[0].pages[0]
|
|
105
107
|
self._page.set_viewport_size(
|
|
106
108
|
{"width": self.display_width, "height": self.display_height}
|
|
@@ -121,7 +123,7 @@ class FleetPlaywrightWrapper:
|
|
|
121
123
|
def _ensure_started(self):
|
|
122
124
|
"""Ensure browser is started before operations."""
|
|
123
125
|
if not self._started:
|
|
124
|
-
raise RuntimeError("Browser not started. Call
|
|
126
|
+
raise RuntimeError("Browser not started. Call browser.start() first.")
|
|
125
127
|
|
|
126
128
|
@property
|
|
127
129
|
def openai_cua_tool(self) -> Dict[str, Any]:
|
|
@@ -237,9 +239,8 @@ class FleetPlaywrightWrapper:
|
|
|
237
239
|
|
|
238
240
|
def _wait(self, ms: int = 1000) -> None:
|
|
239
241
|
"""Wait for specified milliseconds."""
|
|
240
|
-
import asyncio
|
|
241
242
|
|
|
242
|
-
|
|
243
|
+
time.sleep(ms / 1000)
|
|
243
244
|
|
|
244
245
|
# Browser-specific actions
|
|
245
246
|
def _goto(self, url: str) -> None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fleet-python
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: Python SDK for Fleet environments
|
|
5
5
|
Author-email: Fleet AI <nic@fleet.so>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -32,6 +32,7 @@ Requires-Dist: isort>=5.0.0; extra == "dev"
|
|
|
32
32
|
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
33
33
|
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
34
34
|
Requires-Dist: unasync>=0.6.0; extra == "dev"
|
|
35
|
+
Requires-Dist: python-dotenv>=1.1.1; extra == "dev"
|
|
35
36
|
Provides-Extra: playwright
|
|
36
37
|
Requires-Dist: playwright>=1.40.0; extra == "playwright"
|
|
37
38
|
Dynamic: license-file
|
|
@@ -112,3 +113,44 @@ running_instances = flt.env.list_instances(status_filter="running")
|
|
|
112
113
|
# List available environment types
|
|
113
114
|
available_envs = flt.env.list_envs()
|
|
114
115
|
```
|
|
116
|
+
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
### Code Structure
|
|
120
|
+
|
|
121
|
+
This SDK uses `unasync` to maintain both async and sync versions of the code from a single source:
|
|
122
|
+
|
|
123
|
+
- **`fleet/_async/`** - The source code (async version) - **EDIT THIS**
|
|
124
|
+
- **`fleet/`** - The generated sync version - **DO NOT EDIT** (auto-generated)
|
|
125
|
+
|
|
126
|
+
### Making Changes
|
|
127
|
+
|
|
128
|
+
⚠️ **Important**: All code modifications should be made in the `fleet/_async/` directory. The synchronous versions in `fleet/` are automatically generated.
|
|
129
|
+
|
|
130
|
+
1. Make your changes in `fleet/_async/`
|
|
131
|
+
2. Run `make unasync` to generate the sync versions
|
|
132
|
+
3. Test both async and sync versions
|
|
133
|
+
4. Commit all changes (both async source and generated sync files)
|
|
134
|
+
|
|
135
|
+
Example workflow:
|
|
136
|
+
```bash
|
|
137
|
+
# Edit the async source files
|
|
138
|
+
vim fleet/_async/client.py
|
|
139
|
+
|
|
140
|
+
# Generate sync versions
|
|
141
|
+
make unasync
|
|
142
|
+
|
|
143
|
+
# Run tests
|
|
144
|
+
python examples/examle.py
|
|
145
|
+
|
|
146
|
+
# Commit both source and generated files
|
|
147
|
+
git add fleet/_async/ fleet/
|
|
148
|
+
git commit -m "Add new feature"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Why This Structure?
|
|
152
|
+
|
|
153
|
+
- Single source of truth for business logic
|
|
154
|
+
- Automatic sync/async API generation
|
|
155
|
+
- Consistent behavior between sync and async versions
|
|
156
|
+
- Easier maintenance and testing
|
|
@@ -1,36 +1,39 @@
|
|
|
1
|
-
examples/dsl_example.py,sha256=
|
|
2
|
-
examples/example.py,sha256=
|
|
3
|
-
examples/
|
|
4
|
-
examples/
|
|
5
|
-
examples/
|
|
6
|
-
examples/
|
|
7
|
-
examples/
|
|
8
|
-
|
|
1
|
+
examples/dsl_example.py,sha256=3Eu5924a8x61nuSGXqGz8XjPLNKKH8Ye7lSYHSvixtk,5361
|
|
2
|
+
examples/example.py,sha256=FFPfM5Oso7IP9Q8aELpof1J41zslELdHHJhAAck9vLk,1008
|
|
3
|
+
examples/example_client.py,sha256=70HKEhz_Gb79YcvKQauCPdS08AAwjo9unt2dh1jN_Oo,1030
|
|
4
|
+
examples/example_sync.py,sha256=sW8pMU1WsEecGlc_NeQ8BAS1YxOud4iG6MafWGnFeTg,885
|
|
5
|
+
examples/json_tasks_example.py,sha256=EhsJKVWoJFcrqhIIKF5lVrnIqpZDtizQqYblJaOZtmk,2400
|
|
6
|
+
examples/nova_act_example.py,sha256=hZLpObVsiXKQzqGwMZVMf4A2j_z4TYE-YO9pgNmaKPk,836
|
|
7
|
+
examples/openai_example.py,sha256=I2vk_SJN9BkSRQCYRJfbtGJ-HJ2xzQj-lOjwqmLos5M,8234
|
|
8
|
+
examples/openai_simple_example.py,sha256=I42ytIwv0INgDO39pp1MOQSqsJz2YYH8GeNNBaUtq3A,1748
|
|
9
|
+
examples/quickstart.py,sha256=1VT39IRRhemsJgxi0O0gprdpcw7HB4pYO97GAYagIcg,3788
|
|
10
|
+
fleet/__init__.py,sha256=p-0zZMxKoD6dlQ9IGQ753QQWuwcw-RPl4E6HezhKfV4,2111
|
|
9
11
|
fleet/base.py,sha256=t4xkgazl8kEP05JFjNByyf39RvvASRP0GsvxuoqKPY0,1395
|
|
10
|
-
fleet/client.py,sha256=
|
|
12
|
+
fleet/client.py,sha256=xPLlHS14Q2F8jn8e5lSLMUFE6o6ro7oM0XclOjVrxE4,4759
|
|
11
13
|
fleet/exceptions.py,sha256=yG3QWprCw1OnF-vdFBFJWE4m3ftBLBng31Dr__VbjI4,2249
|
|
12
14
|
fleet/models.py,sha256=Jf6Zmk689TPXhTSnVENK_VCw0VsujWzEWsN3T29MQ0k,3713
|
|
13
|
-
fleet/playwright.py,sha256=
|
|
15
|
+
fleet/playwright.py,sha256=BmRvez5DUa0ttAQB084hPAyt9_8WxdzCGBGF-GZbTuQ,8593
|
|
16
|
+
fleet/_async/__init__.py,sha256=AJWCnuo7XKja4yBb8fK2wX7ntciLXQrpzdRHwjTRP6M,62
|
|
14
17
|
fleet/_async/base.py,sha256=hUch1I5oUPgaCXR3IpJ8f_PjigifAZg2-LR7BJdZSo8,1413
|
|
15
|
-
fleet/_async/client.py,sha256=
|
|
18
|
+
fleet/_async/client.py,sha256=T15EwovKCCshr4sF_HeHNdnbIUFoyZqjrN6_tU5o4aY,5010
|
|
16
19
|
fleet/_async/exceptions.py,sha256=yG3QWprCw1OnF-vdFBFJWE4m3ftBLBng31Dr__VbjI4,2249
|
|
17
20
|
fleet/_async/models.py,sha256=Jf6Zmk689TPXhTSnVENK_VCw0VsujWzEWsN3T29MQ0k,3713
|
|
18
|
-
fleet/_async/playwright.py,sha256=
|
|
21
|
+
fleet/_async/playwright.py,sha256=2r4ywuv2ZqT0Qu3-k8A7V4YijeAOHnN8HiqJreLEYGI,8924
|
|
19
22
|
fleet/_async/env/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
-
fleet/_async/env/client.py,sha256=
|
|
23
|
+
fleet/_async/env/client.py,sha256=CO2KuD6FFkP1SdOJ2ehwBKrCdLEFsz5tj3jPR5tVu4U,596
|
|
21
24
|
fleet/_async/instance/__init__.py,sha256=jIt-7EEJ0WM_ipheT_s0lniCbLei6yUdN0qQv1bMJ3E,524
|
|
22
25
|
fleet/_async/instance/base.py,sha256=QgcCTHdcqhi5VQi6_a1uuR-uO2_2Z19-RwVPp1k266A,947
|
|
23
|
-
fleet/_async/instance/client.py,sha256=
|
|
26
|
+
fleet/_async/instance/client.py,sha256=qmX5g6lPrq0b3BQ6LvTApeyquTtCse98Cu_Kwc72y6A,5653
|
|
24
27
|
fleet/_async/instance/models.py,sha256=ZTiue0YOuhuwX8jYfJAoCzGfqjLqqXRLqK1LVFhq6rQ,4183
|
|
25
28
|
fleet/_async/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
29
|
fleet/_async/resources/base.py,sha256=203gD54NP1IvjuSqFo-f7FvrkhtjChggtzrxJK7xf2E,667
|
|
27
30
|
fleet/_async/resources/browser.py,sha256=x11y4aKHogIEv83FByHtExerjV-cDWI3U62349Guq_Q,1368
|
|
28
31
|
fleet/_async/resources/sqlite.py,sha256=sRiII_qJ8X6-FSemlBsXThz4ZPjkNy9wDT8g5UAz2XM,1501
|
|
29
32
|
fleet/env/__init__.py,sha256=_lvYBqieXWmvU_dyPi2seSpLO3AZh5kdprdqFeefkzk,338
|
|
30
|
-
fleet/env/client.py,sha256=
|
|
31
|
-
fleet/instance/__init__.py,sha256=
|
|
33
|
+
fleet/env/client.py,sha256=LVHXnC19bl0zEW20qykC63wJ0nO9gETF6z0_74dCdCo,479
|
|
34
|
+
fleet/instance/__init__.py,sha256=Hr8xPPoqzKOViXZXWmaL6dQ7NOBn-GooTGzoIvGmiE4,514
|
|
32
35
|
fleet/instance/base.py,sha256=U-qW1EQVBo6yvMpP1JeKiPRhCjZ3y3aTsYFhLPNOTtQ,929
|
|
33
|
-
fleet/instance/client.py,sha256=
|
|
36
|
+
fleet/instance/client.py,sha256=2EcuBpq21kUHCFommYdS9Ya-unLn-e8mrdAZBIZea3Q,5467
|
|
34
37
|
fleet/instance/models.py,sha256=ZTiue0YOuhuwX8jYfJAoCzGfqjLqqXRLqK1LVFhq6rQ,4183
|
|
35
38
|
fleet/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
39
|
fleet/resources/base.py,sha256=203gD54NP1IvjuSqFo-f7FvrkhtjChggtzrxJK7xf2E,667
|
|
@@ -40,9 +43,10 @@ fleet/verifiers/__init__.py,sha256=mRMN8x0gDWFJ1MRLqdBtQw0gn_q8kDV3lMLyoiEf1yY,2
|
|
|
40
43
|
fleet/verifiers/code.py,sha256=NJ4OLZnpqLkI1lXY7-5m2GuZklLxMzHUCnRMVyN2_OI,25
|
|
41
44
|
fleet/verifiers/db.py,sha256=tssmvJjDHuBIy8qlL_P5-UdmEFUw2DZcqLsWZ8ot3Xw,27766
|
|
42
45
|
fleet/verifiers/sql_differ.py,sha256=dmiGCFXVMEMbAX519OjhVqgA8ZvhnvdmC1BVpL7QCF0,6490
|
|
43
|
-
fleet_python-0.2.
|
|
46
|
+
fleet_python-0.2.7.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
47
|
+
scripts/fix_sync_imports.py,sha256=b7tRvShgOFqyildqs1qI-Io0gaHappykBI-PSWWqUwE,2941
|
|
44
48
|
scripts/unasync.py,sha256=--Fmaae47o-dZ1HYgX1c3Nvi-rMjcFymTRlJcWWnmpw,725
|
|
45
|
-
fleet_python-0.2.
|
|
46
|
-
fleet_python-0.2.
|
|
47
|
-
fleet_python-0.2.
|
|
48
|
-
fleet_python-0.2.
|
|
49
|
+
fleet_python-0.2.7.dist-info/METADATA,sha256=hWvnoVCE-orcwesjDjMAm01Cjs5XWYpYXLfN9d7Hg44,4321
|
|
50
|
+
fleet_python-0.2.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
51
|
+
fleet_python-0.2.7.dist-info/top_level.txt,sha256=_3DSmTohvSDf3AIP_BYfGzhwO1ECFwuzg83X-wHCx3Y,23
|
|
52
|
+
fleet_python-0.2.7.dist-info/RECORD,,
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Fix imports in sync files after unasync runs."""
|
|
3
|
+
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
def fix_file(filepath: Path) -> bool:
|
|
8
|
+
"""Fix imports and sleep calls in a single file."""
|
|
9
|
+
content = filepath.read_text()
|
|
10
|
+
original = content
|
|
11
|
+
|
|
12
|
+
# Remove asyncio import if it exists
|
|
13
|
+
content = re.sub(r'^import asyncio.*\n', '', content, flags=re.MULTILINE)
|
|
14
|
+
content = re.sub(r'^import asyncio as async_time.*\n', '', content, flags=re.MULTILINE)
|
|
15
|
+
# Also remove indented asyncio imports (like in functions)
|
|
16
|
+
content = re.sub(r'^\s+import asyncio.*\n', '', content, flags=re.MULTILINE)
|
|
17
|
+
|
|
18
|
+
# Fix any remaining asyncio.sleep or async_time.sleep calls
|
|
19
|
+
content = content.replace('asyncio.sleep(', 'time.sleep(')
|
|
20
|
+
content = content.replace('async_time.sleep(', 'time.sleep(')
|
|
21
|
+
|
|
22
|
+
# Fix absolute imports to relative imports for verifiers
|
|
23
|
+
content = content.replace('from fleet.verifiers import', 'from ..verifiers import')
|
|
24
|
+
|
|
25
|
+
# Fix any remaining AsyncFleetPlaywrightWrapper references in docstrings
|
|
26
|
+
content = content.replace('AsyncFleetPlaywrightWrapper', 'FleetPlaywrightWrapper')
|
|
27
|
+
|
|
28
|
+
# Fix playwright imports for sync version
|
|
29
|
+
if 'playwright' in str(filepath):
|
|
30
|
+
# Fix the import statement
|
|
31
|
+
content = content.replace('from playwright.async_api import sync_playwright, Browser, Page',
|
|
32
|
+
'from playwright.sync_api import sync_playwright, Browser, Page')
|
|
33
|
+
content = content.replace('from playwright.async_api import async_playwright, Browser, Page',
|
|
34
|
+
'from playwright.sync_api import sync_playwright, Browser, Page')
|
|
35
|
+
# Replace any remaining async_playwright references
|
|
36
|
+
content = content.replace('async_playwright', 'sync_playwright')
|
|
37
|
+
# Fix await statements in docstrings
|
|
38
|
+
content = content.replace('await browser.start()', 'browser.start()')
|
|
39
|
+
content = content.replace('await browser.screenshot()', 'browser.screenshot()')
|
|
40
|
+
content = content.replace('await browser.close()', 'browser.close()')
|
|
41
|
+
content = content.replace('await fleet.env.make(', 'fleet.env.make(')
|
|
42
|
+
# Fix error message
|
|
43
|
+
content = content.replace('Call await browser.start() first', 'Call browser.start() first')
|
|
44
|
+
|
|
45
|
+
if content != original:
|
|
46
|
+
filepath.write_text(content)
|
|
47
|
+
return True
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
def main():
|
|
51
|
+
"""Fix all sync files."""
|
|
52
|
+
sync_dir = Path(__file__).parent.parent / "fleet"
|
|
53
|
+
|
|
54
|
+
# Files to fix
|
|
55
|
+
files_to_fix = [
|
|
56
|
+
sync_dir / "instance" / "client.py",
|
|
57
|
+
sync_dir / "playwright.py",
|
|
58
|
+
# Add other files here as needed
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
for filepath in files_to_fix:
|
|
62
|
+
if filepath.exists():
|
|
63
|
+
if fix_file(filepath):
|
|
64
|
+
print(f"Fixed {filepath}")
|
|
65
|
+
else:
|
|
66
|
+
print(f"No changes needed for {filepath}")
|
|
67
|
+
|
|
68
|
+
if __name__ == "__main__":
|
|
69
|
+
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|