fleet-python 0.1.0__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/quickstart.py +130 -0
- fleet/__init__.py +42 -0
- fleet/client.py +318 -0
- fleet/config.py +125 -0
- fleet/env/__init__.py +30 -0
- fleet/env/base.py +328 -0
- fleet/env/factory.py +446 -0
- fleet/exceptions.py +73 -0
- fleet/facets/__init__.py +7 -0
- fleet/facets/base.py +223 -0
- fleet/facets/factory.py +29 -0
- fleet/manager_client.py +177 -0
- fleet_python-0.1.0.dist-info/METADATA +110 -0
- fleet_python-0.1.0.dist-info/RECORD +17 -0
- fleet_python-0.1.0.dist-info/WHEEL +5 -0
- fleet_python-0.1.0.dist-info/licenses/LICENSE +201 -0
- fleet_python-0.1.0.dist-info/top_level.txt +2 -0
fleet/facets/base.py
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"""Fleet SDK Base Facet Classes."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import Any, Dict, Optional, TYPE_CHECKING
|
|
5
|
+
from urllib.parse import urlparse
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from ..env.base import Environment
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Facet(ABC):
|
|
12
|
+
"""Base class for all facets in Fleet environments."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, uri: str, environment: "Environment"):
|
|
15
|
+
self.uri = uri
|
|
16
|
+
self.environment = environment
|
|
17
|
+
self._parsed_uri = urlparse(uri)
|
|
18
|
+
self._scheme = self._parsed_uri.scheme
|
|
19
|
+
self._netloc = self._parsed_uri.netloc
|
|
20
|
+
self._path = self._parsed_uri.path
|
|
21
|
+
self._params = self._parsed_uri.params
|
|
22
|
+
self._query = self._parsed_uri.query
|
|
23
|
+
self._fragment = self._parsed_uri.fragment
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def scheme(self) -> str:
|
|
27
|
+
"""Get the URI scheme (e.g., 'sqlite', 'browser', 'file')."""
|
|
28
|
+
return self._scheme
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def netloc(self) -> str:
|
|
32
|
+
"""Get the URI network location."""
|
|
33
|
+
return self._netloc
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def path(self) -> str:
|
|
37
|
+
"""Get the URI path."""
|
|
38
|
+
return self._path
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
async def initialize(self) -> None:
|
|
42
|
+
"""Initialize the facet."""
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
async def close(self) -> None:
|
|
47
|
+
"""Close the facet and clean up resources."""
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
def __repr__(self) -> str:
|
|
51
|
+
return f"{self.__class__.__name__}(uri='{self.uri}')"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class DatabaseFacet(Facet):
|
|
55
|
+
"""Base class for database facets."""
|
|
56
|
+
|
|
57
|
+
@abstractmethod
|
|
58
|
+
async def exec(self, query: str, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
59
|
+
"""Execute a database query.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
query: SQL query to execute
|
|
63
|
+
params: Query parameters
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Query result
|
|
67
|
+
"""
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
@abstractmethod
|
|
71
|
+
async def fetch(self, query: str, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
72
|
+
"""Fetch results from a database query.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
query: SQL query to execute
|
|
76
|
+
params: Query parameters
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Query results
|
|
80
|
+
"""
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class BrowserFacet(Facet):
|
|
85
|
+
"""Base class for browser facets."""
|
|
86
|
+
|
|
87
|
+
@abstractmethod
|
|
88
|
+
async def get_dom(self) -> Dict[str, Any]:
|
|
89
|
+
"""Get the current DOM structure.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
DOM structure as dictionary
|
|
93
|
+
"""
|
|
94
|
+
pass
|
|
95
|
+
|
|
96
|
+
@abstractmethod
|
|
97
|
+
async def get_element(self, selector: str) -> Optional[Dict[str, Any]]:
|
|
98
|
+
"""Get an element by CSS selector.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
selector: CSS selector
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Element data or None if not found
|
|
105
|
+
"""
|
|
106
|
+
pass
|
|
107
|
+
|
|
108
|
+
@abstractmethod
|
|
109
|
+
async def get_elements(self, selector: str) -> list[Dict[str, Any]]:
|
|
110
|
+
"""Get elements by CSS selector.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
selector: CSS selector
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
List of element data
|
|
117
|
+
"""
|
|
118
|
+
pass
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class FileFacet(Facet):
|
|
122
|
+
"""Base class for file system facets."""
|
|
123
|
+
|
|
124
|
+
@abstractmethod
|
|
125
|
+
async def read(self, path: str) -> bytes:
|
|
126
|
+
"""Read file contents.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
path: File path
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
File contents as bytes
|
|
133
|
+
"""
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
@abstractmethod
|
|
137
|
+
async def write(self, path: str, content: bytes) -> None:
|
|
138
|
+
"""Write file contents.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
path: File path
|
|
142
|
+
content: Content to write
|
|
143
|
+
"""
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
@abstractmethod
|
|
147
|
+
async def list_dir(self, path: str) -> list[str]:
|
|
148
|
+
"""List directory contents.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
path: Directory path
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
List of file/directory names
|
|
155
|
+
"""
|
|
156
|
+
pass
|
|
157
|
+
|
|
158
|
+
@abstractmethod
|
|
159
|
+
async def exists(self, path: str) -> bool:
|
|
160
|
+
"""Check if file or directory exists.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
path: File or directory path
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
True if exists, False otherwise
|
|
167
|
+
"""
|
|
168
|
+
pass
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class APIFacet(Facet):
|
|
172
|
+
"""Base class for API facets."""
|
|
173
|
+
|
|
174
|
+
@abstractmethod
|
|
175
|
+
async def get(self, path: str, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
176
|
+
"""Make a GET request.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
path: API endpoint path
|
|
180
|
+
params: Query parameters
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
API response
|
|
184
|
+
"""
|
|
185
|
+
pass
|
|
186
|
+
|
|
187
|
+
@abstractmethod
|
|
188
|
+
async def post(self, path: str, data: Optional[Dict[str, Any]] = None) -> Any:
|
|
189
|
+
"""Make a POST request.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
path: API endpoint path
|
|
193
|
+
data: Request data
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
API response
|
|
197
|
+
"""
|
|
198
|
+
pass
|
|
199
|
+
|
|
200
|
+
@abstractmethod
|
|
201
|
+
async def put(self, path: str, data: Optional[Dict[str, Any]] = None) -> Any:
|
|
202
|
+
"""Make a PUT request.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
path: API endpoint path
|
|
206
|
+
data: Request data
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
API response
|
|
210
|
+
"""
|
|
211
|
+
pass
|
|
212
|
+
|
|
213
|
+
@abstractmethod
|
|
214
|
+
async def delete(self, path: str) -> Any:
|
|
215
|
+
"""Make a DELETE request.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
path: API endpoint path
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
API response
|
|
222
|
+
"""
|
|
223
|
+
pass
|
fleet/facets/factory.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Fleet SDK Facet Factory."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
from urllib.parse import urlparse
|
|
5
|
+
|
|
6
|
+
from .base import Facet
|
|
7
|
+
from ..exceptions import FleetFacetError
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from ..env.base import Environment
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def create_facet(uri: str, environment: "Environment") -> Facet:
|
|
14
|
+
"""Create a facet based on the URI scheme.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
uri: URI identifying the facet (e.g., 'sqlite://crm', 'browser://dom')
|
|
18
|
+
environment: Environment instance
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
Facet instance
|
|
22
|
+
|
|
23
|
+
Raises:
|
|
24
|
+
NotImplementedError: Facet implementations are not yet available
|
|
25
|
+
"""
|
|
26
|
+
parsed = urlparse(uri)
|
|
27
|
+
scheme = parsed.scheme.lower()
|
|
28
|
+
|
|
29
|
+
raise NotImplementedError(f"Facet implementation for scheme '{scheme}' not yet available")
|
fleet/manager_client.py
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Copyright 2025 Fleet AI
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Fleet Manager API Client for per-instance environment management."""
|
|
16
|
+
|
|
17
|
+
import asyncio
|
|
18
|
+
import logging
|
|
19
|
+
from typing import Any, Dict, Optional
|
|
20
|
+
import aiohttp
|
|
21
|
+
from pydantic import BaseModel, Field
|
|
22
|
+
|
|
23
|
+
from .exceptions import (
|
|
24
|
+
FleetAPIError,
|
|
25
|
+
FleetTimeoutError,
|
|
26
|
+
FleetError,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
logger = logging.getLogger(__name__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ManagerHealthResponse(BaseModel):
|
|
33
|
+
"""Response model for manager health checks."""
|
|
34
|
+
|
|
35
|
+
status: str = Field(..., description="Health status")
|
|
36
|
+
timestamp: str = Field(..., description="Timestamp")
|
|
37
|
+
service: str = Field(..., description="Service name")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class TimestampResponse(BaseModel):
|
|
41
|
+
"""Response model for timestamp endpoint."""
|
|
42
|
+
|
|
43
|
+
timestamp: str = Field(..., description="Current timestamp")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class FleetManagerClient:
|
|
47
|
+
"""Client for interacting with Fleet Manager APIs on individual instances."""
|
|
48
|
+
|
|
49
|
+
def __init__(self, base_url: str):
|
|
50
|
+
"""Initialize the manager client.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
base_url: Base URL for the manager API (e.g., https://instanceid.fleetai.com)
|
|
54
|
+
"""
|
|
55
|
+
self._base_url = base_url.rstrip('/')
|
|
56
|
+
self._session: Optional[aiohttp.ClientSession] = None
|
|
57
|
+
|
|
58
|
+
async def __aenter__(self):
|
|
59
|
+
"""Async context manager entry."""
|
|
60
|
+
await self._ensure_session()
|
|
61
|
+
return self
|
|
62
|
+
|
|
63
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
64
|
+
"""Async context manager exit."""
|
|
65
|
+
await self.close()
|
|
66
|
+
|
|
67
|
+
async def _ensure_session(self):
|
|
68
|
+
"""Ensure HTTP session is created."""
|
|
69
|
+
if self._session is None or self._session.closed:
|
|
70
|
+
timeout = aiohttp.ClientTimeout(total=30)
|
|
71
|
+
self._session = aiohttp.ClientSession(
|
|
72
|
+
timeout=timeout,
|
|
73
|
+
connector=aiohttp.TCPConnector(limit=10),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
async def close(self):
|
|
77
|
+
"""Close the HTTP session."""
|
|
78
|
+
if self._session and not self._session.closed:
|
|
79
|
+
await self._session.close()
|
|
80
|
+
self._session = None
|
|
81
|
+
|
|
82
|
+
async def _request(
|
|
83
|
+
self,
|
|
84
|
+
method: str,
|
|
85
|
+
path: str,
|
|
86
|
+
data: Optional[Dict[str, Any]] = None,
|
|
87
|
+
params: Optional[Dict[str, Any]] = None,
|
|
88
|
+
headers: Optional[Dict[str, str]] = None,
|
|
89
|
+
timeout: Optional[float] = None,
|
|
90
|
+
) -> Dict[str, Any]:
|
|
91
|
+
"""Make an HTTP request to the Manager API.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
method: HTTP method (GET, POST, etc.)
|
|
95
|
+
path: API endpoint path
|
|
96
|
+
data: Request body data
|
|
97
|
+
params: Query parameters
|
|
98
|
+
headers: Additional headers
|
|
99
|
+
timeout: Request timeout in seconds
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Response data as dictionary
|
|
103
|
+
|
|
104
|
+
Raises:
|
|
105
|
+
FleetAPIError: If the API returns an error
|
|
106
|
+
FleetTimeoutError: If request times out
|
|
107
|
+
"""
|
|
108
|
+
await self._ensure_session()
|
|
109
|
+
|
|
110
|
+
url = f"{self._base_url}{path}"
|
|
111
|
+
request_headers = headers or {}
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
logger.debug(f"Making {method} request to {url}")
|
|
115
|
+
|
|
116
|
+
async with self._session.request(
|
|
117
|
+
method=method,
|
|
118
|
+
url=url,
|
|
119
|
+
json=data,
|
|
120
|
+
params=params,
|
|
121
|
+
headers=request_headers,
|
|
122
|
+
timeout=aiohttp.ClientTimeout(total=timeout or 30),
|
|
123
|
+
) as response:
|
|
124
|
+
response_data = await response.json() if response.content_type == "application/json" else {}
|
|
125
|
+
|
|
126
|
+
if response.status == 200:
|
|
127
|
+
logger.debug(f"Manager API request successful: {response.status}")
|
|
128
|
+
return response_data
|
|
129
|
+
else:
|
|
130
|
+
error_message = response_data.get("detail", f"Manager API request failed with status {response.status}")
|
|
131
|
+
raise FleetAPIError(
|
|
132
|
+
error_message,
|
|
133
|
+
status_code=response.status,
|
|
134
|
+
response_data=response_data,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
except asyncio.TimeoutError:
|
|
138
|
+
raise FleetTimeoutError(f"Request to {url} timed out")
|
|
139
|
+
|
|
140
|
+
except aiohttp.ClientError as e:
|
|
141
|
+
raise FleetAPIError(f"HTTP client error: {e}")
|
|
142
|
+
|
|
143
|
+
# Health check operations
|
|
144
|
+
async def health_check(self) -> ManagerHealthResponse:
|
|
145
|
+
"""Check the health of the manager API.
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
ManagerHealthResponse object
|
|
149
|
+
"""
|
|
150
|
+
response = await self._request("GET", "/health")
|
|
151
|
+
return ManagerHealthResponse(**response)
|
|
152
|
+
|
|
153
|
+
async def get_timestamp(self) -> TimestampResponse:
|
|
154
|
+
"""Get current timestamp from the manager.
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
TimestampResponse object
|
|
158
|
+
"""
|
|
159
|
+
response = await self._request("GET", "/timestamp")
|
|
160
|
+
return TimestampResponse(**response)
|
|
161
|
+
|
|
162
|
+
async def test_path(self) -> Dict[str, Any]:
|
|
163
|
+
"""Test endpoint to verify path configuration.
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
Test response data
|
|
167
|
+
"""
|
|
168
|
+
response = await self._request("GET", "/test-path")
|
|
169
|
+
return response
|
|
170
|
+
|
|
171
|
+
# Future endpoints can be added here as needed:
|
|
172
|
+
# - log_action()
|
|
173
|
+
# - reset_database()
|
|
174
|
+
# - create_snapshots()
|
|
175
|
+
# - generate_diff()
|
|
176
|
+
# - execute_verifier_function()
|
|
177
|
+
# etc.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fleet-python
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for Fleet environments
|
|
5
|
+
Author-email: Fleet AI <nic@fleet.so>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://fleetai.com
|
|
8
|
+
Project-URL: Documentation, https://docs.fleetai.com
|
|
9
|
+
Project-URL: Repository, https://github.com/fleet-ai/fleet-sdk
|
|
10
|
+
Project-URL: Issues, https://github.com/fleet-ai/fleet-sdk/issues
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Requires-Python: >=3.8
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
29
|
+
Requires-Dist: black>=22.0.0; extra == "dev"
|
|
30
|
+
Requires-Dist: isort>=5.0.0; extra == "dev"
|
|
31
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
32
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# Fleet SDK
|
|
36
|
+
|
|
37
|
+
The Fleet Python SDK provides programmatic access to Fleet's environment infrastructure.
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
Install the Fleet SDK using pip:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install fleet-python
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## API Key Setup
|
|
48
|
+
|
|
49
|
+
Fleet requires an API key for authentication. You can obtain one from the [Fleet Platform](https://fleetai.com/dashboard/api-keys).
|
|
50
|
+
|
|
51
|
+
Set your API key as an environment variable:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
export FLEET_API_KEY="sk_your_key_here"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Basic Usage
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import fleet as flt
|
|
61
|
+
|
|
62
|
+
# Create environment by key
|
|
63
|
+
env = await flt.env.make("fira")
|
|
64
|
+
|
|
65
|
+
# Reset environment with seed and options
|
|
66
|
+
await env.reset(
|
|
67
|
+
seed=42,
|
|
68
|
+
timestamp=datetime.now()
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Access environment state ('crm' is the resource id for a sqlite database)
|
|
72
|
+
sql = env.state("sqlite://crm")
|
|
73
|
+
await sql.exec("UPDATE customers SET status = 'active' WHERE id = 123")
|
|
74
|
+
|
|
75
|
+
# Clean up
|
|
76
|
+
await env.close()
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Environment Management
|
|
80
|
+
|
|
81
|
+
### Creating Instances
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
# Create environment instance with explicit version
|
|
85
|
+
env = await flt.env.make("fira:v1.2.5")
|
|
86
|
+
|
|
87
|
+
# Create environment instance with default (latest) version
|
|
88
|
+
env = await flt.env.make("fira")
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Connecting to Existing Instances
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
# Connect to a running instance
|
|
96
|
+
env = await flt.env.get("env_instance_id")
|
|
97
|
+
|
|
98
|
+
# List all running instances
|
|
99
|
+
instances = await flt.env.list_instances()
|
|
100
|
+
for instance in instances:
|
|
101
|
+
print(f"Instance: {instance.instance_id}")
|
|
102
|
+
print(f"Type: {instance.environment_type}")
|
|
103
|
+
print(f"Status: {instance.status}")
|
|
104
|
+
|
|
105
|
+
# Filter instances by status (running, pending, stopped, error)
|
|
106
|
+
running_instances = await flt.env.list_instances(status_filter="running")
|
|
107
|
+
|
|
108
|
+
# List available environment types
|
|
109
|
+
available_envs = await flt.env.list_envs()
|
|
110
|
+
```
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
examples/quickstart.py,sha256=AnLlLQYRfrP7y2J69d1HZRlZsjJT-KeBu897MoNfqYM,4671
|
|
2
|
+
fleet/__init__.py,sha256=WhanDP1kC_K84nrEe9ER1iyODW2344wghQ8Rgdi-JmA,1441
|
|
3
|
+
fleet/client.py,sha256=nBjUV901oyR5uE0WAwHEE-xsgyntesGRiLVhVWf793o,12071
|
|
4
|
+
fleet/config.py,sha256=xlKv-gr38oBcyltQiKjgLzxV-JSd3b4x5oxevOjioME,3768
|
|
5
|
+
fleet/exceptions.py,sha256=yG3QWprCw1OnF-vdFBFJWE4m3ftBLBng31Dr__VbjI4,2249
|
|
6
|
+
fleet/manager_client.py,sha256=o01MuTAoeXssI23SSIwsAHM8ck1G6VsOluD_emcpFnE,5900
|
|
7
|
+
fleet/env/__init__.py,sha256=yKJ-35vAVU4VWWkZMDFeElF9uMzsahBm2K-IumOkciU,570
|
|
8
|
+
fleet/env/base.py,sha256=Ry-1t2cyn2EMlpEtO3XJ89FzK7Q471tsZ8WaluIacK8,12046
|
|
9
|
+
fleet/env/factory.py,sha256=BH6ILmc5WvyNanqSf6RqZXR6SgixMoDw5tOnR0PqVhM,13920
|
|
10
|
+
fleet/facets/__init__.py,sha256=oXU7Tkcx1ETlto4mLUwrjj5-5EcsM-lqAqksJMpmDkE,84
|
|
11
|
+
fleet/facets/base.py,sha256=mJAnRiboGWRn5eSjKM6QZTOPDGDiMrl2kwJbONZ3yq0,5400
|
|
12
|
+
fleet/facets/factory.py,sha256=7OecnXJUafsM9mJcNPHXV5djUOUNg8I6p12sfXGCb4g,782
|
|
13
|
+
fleet_python-0.1.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
14
|
+
fleet_python-0.1.0.dist-info/METADATA,sha256=I6IGquclMRBeM6IVAKs_uQY-8rC7McfSrE850zCcHfU,3040
|
|
15
|
+
fleet_python-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
16
|
+
fleet_python-0.1.0.dist-info/top_level.txt,sha256=AOyXOrBXUjPcH4BumElz_D95kiWKNIpUbUPFP_9gCLk,15
|
|
17
|
+
fleet_python-0.1.0.dist-info/RECORD,,
|