fleet-python 0.2.66b4__py3-none-any.whl → 0.2.68__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.

fleet/tasks.py CHANGED
@@ -202,23 +202,25 @@ class Task(BaseModel):
202
202
  )
203
203
  self.verifier = verifier
204
204
 
205
- def make_env(self, region: Optional[str] = None):
205
+ def make_env(
206
+ self,
207
+ region: Optional[str] = None,
208
+ image_type: Optional[str] = None,
209
+ ttl_seconds: Optional[int] = None,
210
+ run_id: Optional[str] = None,
211
+ ):
206
212
  """Create an environment instance for this task's environment.
207
213
 
208
- Uses the task's env_id (and version if present) to create the env.
214
+ Alias for make() method. Uses the task's env_id (and version if present) to create the env.
209
215
  """
210
- if not self.env_id:
211
- raise ValueError("Task has no env_id defined")
212
- # Deferred import to avoid circular dependencies
213
- from .client import Fleet
214
-
215
- return Fleet().make(env_key=self.env_key, region=region)
216
+ return self.make(region=region, image_type=image_type, ttl_seconds=ttl_seconds, run_id=run_id)
216
217
 
217
218
  def make(
218
219
  self,
219
220
  region: Optional[str] = None,
220
221
  image_type: Optional[str] = None,
221
222
  ttl_seconds: Optional[int] = None,
223
+ run_id: Optional[str] = None,
222
224
  ):
223
225
  """Create an environment instance with task's configuration.
224
226
 
@@ -226,11 +228,13 @@ class Task(BaseModel):
226
228
  - env_key (env_id + version)
227
229
  - data_key (data_id + data_version, if present)
228
230
  - env_variables (if present)
231
+ - run_id (if present)
229
232
 
230
233
  Args:
231
234
  region: Optional AWS region for the environment
232
235
  image_type: Optional image type for the environment
233
236
  ttl_seconds: Optional TTL in seconds for the instance
237
+ run_id: Optional run ID to group instances
234
238
 
235
239
  Returns:
236
240
  Environment instance configured for this task
@@ -238,7 +242,7 @@ class Task(BaseModel):
238
242
  Example:
239
243
  task = fleet.Task(key="my-task", prompt="...", env_id="my-env",
240
244
  data_id="my-data", data_version="v1.0")
241
- env = task.make(region="us-west-2")
245
+ env = task.make(region="us-west-2", run_id="my-batch-123")
242
246
  """
243
247
  if not self.env_id:
244
248
  raise ValueError("Task has no env_id defined")
@@ -253,6 +257,7 @@ class Task(BaseModel):
253
257
  env_variables=self.env_variables if self.env_variables else None,
254
258
  image_type=image_type,
255
259
  ttl_seconds=ttl_seconds,
260
+ run_id=run_id,
256
261
  )
257
262
 
258
263
 
@@ -272,14 +277,17 @@ def verifier_from_string(
272
277
  """
273
278
  try:
274
279
  import inspect
280
+ import re
275
281
  from .verifiers import SyncVerifierFunction
276
282
  from .verifiers.code import TASK_SUCCESSFUL_SCORE, TASK_FAILED_SCORE
277
283
  from .verifiers.db import IgnoreConfig
278
- from .verifiers.parsing import parse_and_validate_verifier
279
284
 
280
- # Validate the code and extract function name
281
- # This ensures no arbitrary code execution during import
282
- func_name = parse_and_validate_verifier(verifier_func)
285
+ # Strip @verifier decorator if present to avoid double-wrapping
286
+ # Remove lines like: @verifier(key="...")
287
+ cleaned_code = re.sub(r"@verifier\([^)]*\)\s*\n", "", verifier_func)
288
+ # Also remove the verifier import if present
289
+ cleaned_code = re.sub(r"from fleet import.*verifier.*\n", "", cleaned_code)
290
+ cleaned_code = re.sub(r"import.*verifier.*\n", "", cleaned_code)
283
291
 
284
292
  # Create a globals namespace with all required imports
285
293
  exec_globals = globals().copy()
@@ -295,18 +303,20 @@ def verifier_from_string(
295
303
  # Create a local namespace for executing the code
296
304
  local_namespace = {}
297
305
 
298
- # Execute the verifier code in the namespace
299
- # This is now safe because we validated it contains only declarative code
300
- exec(verifier_func, exec_globals, local_namespace)
306
+ # Execute the cleaned verifier code in the namespace
307
+ exec(cleaned_code, exec_globals, local_namespace)
301
308
 
302
- # Get the function by the parsed function name
303
- func_obj = local_namespace.get(func_name)
309
+ # Find the function that was defined (not imported)
310
+ # Functions defined via exec have co_filename == '<string>'
311
+ # Imported functions have their actual module file path
312
+ func_obj = None
313
+ for name, obj in local_namespace.items():
314
+ if inspect.isfunction(obj) and obj.__code__.co_filename == "<string>":
315
+ func_obj = obj
316
+ break
304
317
 
305
318
  if func_obj is None:
306
- raise ValueError(f"Function '{func_name}' not found in verifier code")
307
-
308
- if not inspect.isfunction(func_obj):
309
- raise ValueError(f"'{func_name}' is not a function")
319
+ raise ValueError("No function found in verifier code")
310
320
 
311
321
  # Create an SyncVerifierFunction instance with raw code
312
322
  verifier_instance = SyncVerifierFunction(
@@ -384,7 +394,7 @@ def load_tasks(
384
394
 
385
395
 
386
396
  def update_task(
387
- task_key: str, prompt: Optional[str] = None, verifier_code: Optional[str] = None
397
+ task_key: str, prompt: Optional[str] = None, verifier_code: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None
388
398
  ):
389
399
  """Convenience function to update an existing task.
390
400
 
@@ -392,6 +402,7 @@ def update_task(
392
402
  task_key: The key of the task to update
393
403
  prompt: New prompt text for the task (optional)
394
404
  verifier_code: Python code for task verification (optional)
405
+ metadata: Additional metadata for the task (optional)
395
406
 
396
407
  Returns:
397
408
  TaskResponse containing the updated task details
@@ -399,16 +410,19 @@ def update_task(
399
410
  Examples:
400
411
  response = fleet.update_task("my-task", prompt="New prompt text")
401
412
  response = fleet.update_task("my-task", verifier_code="def verify(env): return True")
413
+ response = fleet.update_task("my-task", metadata={"seed": 42, "story": "Updated story"})
402
414
  """
403
415
  from .global_client import get_client
404
416
 
405
417
  client = get_client()
406
418
  return client.update_task(
407
- task_key=task_key, prompt=prompt, verifier_code=verifier_code
419
+ task_key=task_key, prompt=prompt, verifier_code=verifier_code, metadata=metadata
408
420
  )
409
421
 
410
422
 
411
- def get_task(task_key: str, version_id: Optional[str] = None, team_id: Optional[str] = None):
423
+ def get_task(
424
+ task_key: str, version_id: Optional[str] = None, team_id: Optional[str] = None
425
+ ):
412
426
  """Convenience function to get a task by key and optional version.
413
427
 
414
428
  Args:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fleet-python
3
- Version: 0.2.66b4
3
+ Version: 0.2.68
4
4
  Summary: Python SDK for Fleet environments
5
5
  Author-email: Fleet AI <nic@fleet.so>
6
6
  License: Apache-2.0
@@ -11,9 +11,9 @@ examples/example_sync.py,sha256=EkuWmUzB1ZsBJQk6ZRflB793rKsuRHeSg5HJZHVhBB0,975
11
11
  examples/example_task.py,sha256=dhG6STAkNsTdHs9cO1RFH9WfuvRmq5bRC211hTeFrk8,7088
12
12
  examples/example_tasks.py,sha256=xTL8UWVAuolSX6swskfrAcmDrLIzn45dJ7YPWCwoEBU,514
13
13
  examples/example_verifier.py,sha256=0vwNITIG3m4CkSPwIxNXcGx9TqrxEsCGqK2A8keKZMM,2392
14
- examples/export_tasks.py,sha256=cJ_8xND7Q3IOM1JfJPR-DH3aLfHo_KmKJeO-1IVUFrQ,3237
14
+ examples/export_tasks.py,sha256=Sk2Id4i5tZeVs4ZFQoAn-ABFZv7ewyv4pqtZ-Z-tIEI,3574
15
15
  examples/gemini_example.py,sha256=qj9WDazQTYNiRHNeUg9Tjkp33lJMwbx8gDfpFe1sDQo,16180
16
- examples/import_tasks.py,sha256=Duh7T0HUuqsYUZ6LK2AXF3eP0zfSj1izkI5-1p09d9w,11041
16
+ examples/import_tasks.py,sha256=McF5MbHenPZ7HTjQfNoHHevot0EBILMSsWtroicVT30,11619
17
17
  examples/json_tasks_example.py,sha256=CYPESGGtOo0fmsDdLidujTfsE4QlJHw7rOhyVqPJ_Ls,5329
18
18
  examples/nova_act_example.py,sha256=rH23Lp74Okf0rn8ynMdWjK2aviEf5NLPH4k_53Pyxho,831
19
19
  examples/openai_example.py,sha256=dEWERrTEP5xBiGkLkQjBQGd2NqoxX6gcW6XteBPsWFQ,8231
@@ -23,22 +23,22 @@ examples/quickstart.py,sha256=1VT39IRRhemsJgxi0O0gprdpcw7HB4pYO97GAYagIcg,3788
23
23
  examples/test_cdp_logging.py,sha256=AkCwQCgOTQEI8w3v0knWK_4eXMph7L9x07wj9yIYM10,2836
24
24
  fleet/__init__.py,sha256=yC4HIcbtPAPOgI0lLri3l8nbXkNee9JOihKAc7SXYkY,4201
25
25
  fleet/base.py,sha256=bc-340sTpq_DJs7yQ9d2pDWnmJFmA1SwDB9Lagvqtb4,9182
26
- fleet/client.py,sha256=3fcUTBOB8z6nwL07HMXSjajSH_pb2_3gvo2KdGxzxdo,32579
26
+ fleet/client.py,sha256=niWdLmALTmLXHMnIZ4PEwyU6T28dxvtDXeLf-0DS_DE,33868
27
27
  fleet/config.py,sha256=uY02ZKxVoXqVDta-0IMWaYJeE1CTXF_fA9NI6QUutmU,319
28
28
  fleet/exceptions.py,sha256=fUmPwWhnT8SR97lYsRq0kLHQHKtSh2eJS0VQ2caSzEI,5055
29
29
  fleet/global_client.py,sha256=frrDAFNM2ywN0JHLtlm9qbE1dQpnQJsavJpb7xSR_bU,1072
30
- fleet/models.py,sha256=AuSApLRN6aIDTOuJ4mGUyS1K1oLG9Q2AzjIE0Zj61MY,13586
31
- fleet/tasks.py,sha256=2EfhYt7W7qOyACyRoPpne0a6KN78_hplBM4oIecI_I4,17253
30
+ fleet/models.py,sha256=GUL61DOD4XDT588T1a-EV7R1kh1w4q_JRLnX1rEI5ek,13911
31
+ fleet/tasks.py,sha256=iwwvN2o1IWT-9zxmAMBHfT12rfX2Hm0DkfUlrPTs298,17956
32
32
  fleet/types.py,sha256=L4Y82xICf1tzyCLqhLYUgEoaIIS5h9T05TyFNHSWs3s,652
33
33
  fleet/_async/__init__.py,sha256=5oOTmh16UsPWL2gDKKWkj2j5WGNeUhMzbQFWjX21jsc,8310
34
34
  fleet/_async/base.py,sha256=oisVTQsx0M_yTmyQJc3oij63uKZ97MHz-xYFsWXxQE8,9202
35
- fleet/_async/client.py,sha256=w_g0aOLfyyK_OojjGVe3TgyQQsWxnybJRFMLOtsb0p8,33027
35
+ fleet/_async/client.py,sha256=ien5Xs1s4EetFAFExq7Vp_25lN2aVqEQyyDhYy3SJ00,34353
36
36
  fleet/_async/exceptions.py,sha256=fUmPwWhnT8SR97lYsRq0kLHQHKtSh2eJS0VQ2caSzEI,5055
37
37
  fleet/_async/global_client.py,sha256=4WskpLHbsDEgWW7hXMD09W-brkp4euy8w2ZJ88594rQ,1103
38
- fleet/_async/models.py,sha256=6WMN--LJFV-A5L2jW8Y6q7HQfub7qGxGoVkPQhvS_jw,13358
39
- fleet/_async/tasks.py,sha256=74GNmI-sFUaLcUtmApsXJBk-Sb0LoiLnN5Ywj24unv4,17272
38
+ fleet/_async/models.py,sha256=-3xv2QyoHsvYcWmdKLf9Z93md8XB17DBeJCxdRCB3bo,13571
39
+ fleet/_async/tasks.py,sha256=8d65DBMhmHNaLer1FhttUWK4WLS1SU5Hx9_nALMwM4Y,18002
40
40
  fleet/_async/env/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
- fleet/_async/env/client.py,sha256=hUwrKTAkTAbO94_pDaAH8LyvlS9q-7oT7ZRrNo03LNs,1309
41
+ fleet/_async/env/client.py,sha256=Qv0QiW--ZMAMnz_IPYbYtokGP08x4PvSmkwde8rPCNk,2093
42
42
  fleet/_async/instance/__init__.py,sha256=PtmJq8J8bh0SOQ2V55QURz5GJfobozwtQoqhaOk3_tI,515
43
43
  fleet/_async/instance/base.py,sha256=3qUBuUR8OVS36LzdP6KyZzngtwPKYO09HoY6Ekxp-KA,1625
44
44
  fleet/_async/instance/client.py,sha256=kcrmLZciQxvPSfTtbEq5LIbhscwDHg6WIiNcPyM4L9w,6085
@@ -50,8 +50,8 @@ fleet/_async/resources/sqlite.py,sha256=up_umepfyX9PDFsnmEMJLjsj7bLa6a3wizZOgMGk
50
50
  fleet/_async/verifiers/__init__.py,sha256=1WTlCNq4tIFbbXaQu5Bf2WppZq0A8suhtZbxMTSOwxI,465
51
51
  fleet/_async/verifiers/bundler.py,sha256=Sq0KkqEhM5Ng2x8R6Z4puXvQ8FMlEO7D3-ldBLktPi4,26205
52
52
  fleet/_async/verifiers/verifier.py,sha256=IiHX028s6ux0kb2FR0Z5zJangl_IDh6cemXsUN2ktUU,14152
53
- fleet/env/__init__.py,sha256=cS9zCYobM5jypppDMZIQMYd6hOg5f4sgqRXEQ67pckk,676
54
- fleet/env/client.py,sha256=Lu0pGia3Rcull83BFhB1nccAHXbUEGFKl3BUSkoKbr4,1143
53
+ fleet/env/__init__.py,sha256=sSjD6vk8LzC_pxoXuRc8-ACqeX4PLm1FBWnWxpOhUS8,812
54
+ fleet/env/client.py,sha256=l2vI_BBrSXmyk2un3F1-QDcL-iv2OdBxTdYOdOioF0Q,1881
55
55
  fleet/instance/__init__.py,sha256=CyWUkbGAK-DBPw4DC4AnCW-MqqheGhZMA5QSRVu-ws4,479
56
56
  fleet/instance/base.py,sha256=OYqzBwZFfTX9wlBGSG5gljqj98NbiJeKIfFJ3uj5I4s,1587
57
57
  fleet/instance/client.py,sha256=XM_Qmd7pUzC3-dCMTh6orTEsGeWJXbKueBlvcWcSUuI,5897
@@ -67,16 +67,14 @@ fleet/verifiers/code.py,sha256=A1i_UabZspbyj1awzKVQ_HRxgMO3fU7NbkxYyTrp7So,48
67
67
  fleet/verifiers/db.py,sha256=LAh1HambBInH_D9q9E2Z41YNkCOI9JJfpWPFqztjpfQ,27922
68
68
  fleet/verifiers/decorator.py,sha256=nAP3O8szXu7md_kpwpz91hGSUNEVLYjwZQZTkQlV1DM,3260
69
69
  fleet/verifiers/parse.py,sha256=qz9AfJrTbjlg-LU-lE8Ciqi7Yt2a8-cs17FdpjTLhMk,8550
70
- fleet/verifiers/parsing.py,sha256=EzlfHLogHPC1i5pfsF3ZCBJ8NY3s1uvz7v59CfcuMtI,3713
71
70
  fleet/verifiers/sql_differ.py,sha256=TqTLWyK3uOyLbitT6HYzYEzuSFC39wcyhgk3rcm__k8,6525
72
71
  fleet/verifiers/verifier.py,sha256=_lcxXVm8e0xRrK2gNJy9up7pW1zOkPRY5n5lQ85S8jg,14197
73
- fleet_python-0.2.66b4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
72
+ fleet_python-0.2.68.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
74
73
  scripts/fix_sync_imports.py,sha256=X9fWLTpiPGkSHsjyQUDepOJkxOqw1DPj7nd8wFlFqLQ,8368
75
74
  scripts/unasync.py,sha256=vWVQxRWX8SRZO5cmzEhpvnG_REhCWXpidIGIpWmEcvI,696
76
75
  tests/__init__.py,sha256=Re1SdyxH8NfyL1kjhi7SQkGP1mYeWB-D6UALqdIMd8I,35
77
76
  tests/test_verifier_from_string.py,sha256=Lxi3TpFHFb-hG4-UhLKZJkqo84ax9YJY8G6beO-1erM,13581
78
- tests/test_verifier_security.py,sha256=AvjWTVV-VlWaysNkHcRz1_UZxjYZYlr4ynM6uy2o9eM,12821
79
- fleet_python-0.2.66b4.dist-info/METADATA,sha256=n80m0SKUQVigmTJTOqzsL984VJD_e5n75aSrIjN298I,3306
80
- fleet_python-0.2.66b4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
81
- fleet_python-0.2.66b4.dist-info/top_level.txt,sha256=qb1zIbtEktyhRFZdqVytwg54l64qtoZL0wjHB4bUg3c,29
82
- fleet_python-0.2.66b4.dist-info/RECORD,,
77
+ fleet_python-0.2.68.dist-info/METADATA,sha256=3OtKPA7XpF59sT-kEEUPKEdBFJp8GLVStE5kZJLJP84,3304
78
+ fleet_python-0.2.68.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
79
+ fleet_python-0.2.68.dist-info/top_level.txt,sha256=qb1zIbtEktyhRFZdqVytwg54l64qtoZL0wjHB4bUg3c,29
80
+ fleet_python-0.2.68.dist-info/RECORD,,
@@ -1,106 +0,0 @@
1
- """Verifier code parsing and validation utilities."""
2
-
3
- import ast
4
- from typing import Set
5
-
6
-
7
- def parse_and_validate_verifier(code: str) -> str:
8
- """Parse and validate verifier code, returning the first function name.
9
-
10
- This function ensures that the verifier code only contains safe declarative
11
- statements and does not execute arbitrary code during import.
12
-
13
- Args:
14
- code: Python code string containing the verifier function
15
-
16
- Returns:
17
- Name of the first function found in the code
18
-
19
- Raises:
20
- ValueError: If code is invalid or contains unsafe statements
21
- SyntaxError: If code has syntax errors
22
- """
23
- try:
24
- tree = ast.parse(code)
25
- except SyntaxError as e:
26
- raise SyntaxError(f"Syntax error in verifier code: {e}")
27
-
28
- first_function_name = None
29
-
30
- for node in tree.body:
31
- # Check for function definitions
32
- if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
33
- # Validate that decorators don't contain function calls
34
- for decorator in node.decorator_list:
35
- if _contains_call(decorator):
36
- raise ValueError(
37
- f"Line {node.lineno}: Function decorators with function calls "
38
- f"are not allowed. Decorators execute during import and could "
39
- f"run arbitrary code."
40
- )
41
-
42
- if first_function_name is None:
43
- first_function_name = node.name
44
- continue
45
-
46
- # Allow imports
47
- if isinstance(node, (ast.Import, ast.ImportFrom)):
48
- continue
49
-
50
- # Allow class definitions
51
- if isinstance(node, ast.ClassDef):
52
- continue
53
-
54
- # Allow docstrings and other expression statements (but not calls)
55
- if isinstance(node, ast.Expr):
56
- if isinstance(node.value, ast.Constant):
57
- # Docstring or constant expression - safe
58
- continue
59
- else:
60
- # Check if it's a call or other dangerous expression
61
- raise ValueError(
62
- f"Line {node.lineno}: Expression statements that are not "
63
- f"constants are not allowed at module level. Found: {ast.dump(node.value)}"
64
- )
65
-
66
- # Allow variable assignments, but check the value
67
- if isinstance(node, (ast.Assign, ast.AnnAssign)):
68
- # Check if the assignment value contains any function calls
69
- if _contains_call(node.value if isinstance(node, ast.AnnAssign) else node.value):
70
- raise ValueError(
71
- f"Line {node.lineno}: Variable assignments with function calls "
72
- f"are not allowed at module level. This prevents arbitrary code "
73
- f"execution during import."
74
- )
75
- continue
76
-
77
- # If we get here, it's an unsupported statement type
78
- raise ValueError(
79
- f"Line {node.lineno}: Unsupported statement type at module level: "
80
- f"{node.__class__.__name__}. Only imports, function/class definitions, "
81
- f"and constant assignments are allowed."
82
- )
83
-
84
- if first_function_name is None:
85
- raise ValueError("No function found in verifier code")
86
-
87
- return first_function_name
88
-
89
-
90
- def _contains_call(node: ast.AST) -> bool:
91
- """Recursively check if an AST node contains any Call nodes.
92
-
93
- Args:
94
- node: AST node to check
95
-
96
- Returns:
97
- True if the node or any of its children is a Call node
98
- """
99
- if isinstance(node, ast.Call):
100
- return True
101
-
102
- for child in ast.walk(node):
103
- if isinstance(child, ast.Call):
104
- return True
105
-
106
- return False