dslighting 1.3.1__tar.gz → 1.3.6__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.
Files changed (86) hide show
  1. {dslighting-1.3.1 → dslighting-1.3.6}/PKG-INFO +1 -1
  2. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/services/llm.py +2 -1
  3. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/services/llm_single.py +2 -1
  4. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/services/sandbox.py +34 -5
  5. {dslighting-1.3.1 → dslighting-1.3.6}/dslighting/__init__.py +10 -3
  6. {dslighting-1.3.1 → dslighting-1.3.6}/dslighting/core/agent.py +6 -0
  7. {dslighting-1.3.1 → dslighting-1.3.6}/dslighting/core/config_builder.py +30 -1
  8. {dslighting-1.3.1 → dslighting-1.3.6}/dslighting/core/data_loader.py +38 -6
  9. {dslighting-1.3.1 → dslighting-1.3.6}/dslighting.egg-info/PKG-INFO +1 -1
  10. {dslighting-1.3.1 → dslighting-1.3.6}/pyproject.toml +1 -1
  11. {dslighting-1.3.1 → dslighting-1.3.6}/README.md +0 -0
  12. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/__init__.py +0 -0
  13. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/benchmark/__init__.py +0 -0
  14. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/benchmark/benchmark.py +0 -0
  15. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/benchmark/datasci.py +0 -0
  16. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/benchmark/mle.py +0 -0
  17. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/benchmark/sciencebench.py +0 -0
  18. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/common/__init__.py +0 -0
  19. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/common/constants.py +0 -0
  20. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/common/exceptions.py +0 -0
  21. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/common/typing.py +0 -0
  22. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/config.py +0 -0
  23. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/models/__init__.py +0 -0
  24. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/models/candidates.py +0 -0
  25. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/models/formats.py +0 -0
  26. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/models/task.py +0 -0
  27. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/operators/__init__.py +0 -0
  28. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/operators/aflow_ops.py +0 -0
  29. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/operators/autokaggle_ops.py +0 -0
  30. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/operators/automind_ops.py +0 -0
  31. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/operators/base.py +0 -0
  32. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/operators/code.py +0 -0
  33. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/operators/dsagent_ops.py +0 -0
  34. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/operators/llm_basic.py +0 -0
  35. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/prompts/__init__.py +0 -0
  36. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/prompts/aflow_prompt.py +0 -0
  37. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/prompts/aide_prompt.py +0 -0
  38. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/prompts/autokaggle_prompt.py +0 -0
  39. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/prompts/automind_prompt.py +0 -0
  40. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/prompts/common.py +0 -0
  41. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/prompts/data_interpreter_prompt.py +0 -0
  42. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/prompts/dsagent_prompt.py +0 -0
  43. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/runner.py +0 -0
  44. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/services/__init__.py +0 -0
  45. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/services/data_analyzer.py +0 -0
  46. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/services/states/__init__.py +0 -0
  47. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/services/states/autokaggle_state.py +0 -0
  48. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/services/states/base.py +0 -0
  49. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/services/states/dsa_log.py +0 -0
  50. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/services/states/experience.py +0 -0
  51. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/services/states/journal.py +0 -0
  52. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/services/states/operator_library.py +0 -0
  53. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/services/vdb.py +0 -0
  54. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/services/workspace.py +0 -0
  55. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/tasks/__init__.py +0 -0
  56. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/tasks/handlers.py +0 -0
  57. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/templates/open_ended/grade_template.py +0 -0
  58. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/tools/__init__.py +0 -0
  59. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/utils/__init__.py +0 -0
  60. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/utils/context.py +0 -0
  61. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/utils/dynamic_import.py +0 -0
  62. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/utils/parsing.py +0 -0
  63. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/workflows/__init__.py +0 -0
  64. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/workflows/base.py +0 -0
  65. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/workflows/factory.py +0 -0
  66. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/workflows/manual/__init__.py +0 -0
  67. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/workflows/manual/autokaggle_workflow.py +0 -0
  68. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/workflows/manual/data_interpreter_workflow.py +0 -0
  69. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/workflows/manual/deepanalyze_workflow.py +0 -0
  70. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/workflows/manual/dsagent_workflow.py +0 -0
  71. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/workflows/search/__init__.py +0 -0
  72. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/workflows/search/aflow_workflow.py +0 -0
  73. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/workflows/search/aide_workflow.py +0 -0
  74. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/workflows/search/automind_workflow.py +0 -0
  75. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/workflows/templates/__init__.py +0 -0
  76. {dslighting-1.3.1 → dslighting-1.3.6}/dsat/workflows/templates/basic_kaggle_loop.py +0 -0
  77. {dslighting-1.3.1 → dslighting-1.3.6}/dslighting/core/__init__.py +0 -0
  78. {dslighting-1.3.1 → dslighting-1.3.6}/dslighting/core/task_detector.py +0 -0
  79. {dslighting-1.3.1 → dslighting-1.3.6}/dslighting/utils/__init__.py +0 -0
  80. {dslighting-1.3.1 → dslighting-1.3.6}/dslighting/utils/defaults.py +0 -0
  81. {dslighting-1.3.1 → dslighting-1.3.6}/dslighting.egg-info/SOURCES.txt +0 -0
  82. {dslighting-1.3.1 → dslighting-1.3.6}/dslighting.egg-info/dependency_links.txt +0 -0
  83. {dslighting-1.3.1 → dslighting-1.3.6}/dslighting.egg-info/requires.txt +0 -0
  84. {dslighting-1.3.1 → dslighting-1.3.6}/dslighting.egg-info/top_level.txt +0 -0
  85. {dslighting-1.3.1 → dslighting-1.3.6}/setup.cfg +0 -0
  86. {dslighting-1.3.1 → dslighting-1.3.6}/tests/test_dslighting_api.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dslighting
3
- Version: 1.3.1
3
+ Version: 1.3.6
4
4
  Summary: Simplified API for Data Science Agent Automation
5
5
  Author: DSLighting Team
6
6
  License: AGPL-3.0
@@ -43,7 +43,8 @@ def _load_custom_model_pricing():
43
43
  config = yaml.safe_load(f)
44
44
  return config.get('custom_model_pricing', {})
45
45
  else:
46
- logger.warning(f"Config file not found at {config_yaml_path}")
46
+ # Changed to debug to avoid confusing warnings for pip-installed packages
47
+ logger.debug(f"Config file not found at {config_yaml_path} (this is expected for pip-installed packages)")
47
48
  return {}
48
49
  except Exception as e:
49
50
  logger.error(f"Failed to load cost configuration: {e}")
@@ -43,7 +43,8 @@ def _load_custom_model_pricing():
43
43
  config = yaml.safe_load(f)
44
44
  return config.get('custom_model_pricing', {})
45
45
  else:
46
- logger.warning(f"Config file not found at {config_yaml_path}")
46
+ # Changed to debug to avoid confusing warnings for pip-installed packages
47
+ logger.debug(f"Config file not found at {config_yaml_path} (this is expected for pip-installed packages)")
47
48
  return {}
48
49
  except Exception as e:
49
50
  logger.error(f"Failed to load cost configuration: {e}")
@@ -245,17 +245,46 @@ class ProcessIsolatedNotebookExecutor:
245
245
  class SandboxService:
246
246
  """
247
247
  Provides unified access to isolated script and notebook code execution environments.
248
+
249
+ Args:
250
+ workspace: Workspace service for managing files
251
+ timeout: Default timeout for script execution (seconds)
252
+ auto_matplotlib: Automatically inject matplotlib backend (default: False).
253
+ Set to True for Web UI environments that need visualization.
254
+ Set to False for standalone package usage.
248
255
  """
249
- def __init__(self, workspace: WorkspaceService, timeout: int = 600):
256
+ def __init__(
257
+ self,
258
+ workspace: WorkspaceService,
259
+ timeout: int = 600,
260
+ auto_matplotlib: bool = False
261
+ ):
250
262
  self.workspace = workspace
251
263
  self.timeout = timeout
264
+ self.auto_matplotlib = auto_matplotlib # Store matplotlib injection preference
252
265
  self.execution_history: List[Dict[str, Any]] = []
253
266
 
254
267
  def run_script(self, script_code: str, timeout: Optional[int] = None) -> ExecutionResult:
255
- """Runs a Python script within the sandbox workspace."""
256
- # Force non-interactive backend for matplotlib to prevent blocking plt.show()
257
- fixed_code = "import matplotlib\nmatplotlib.use('Agg')\n" + script_code
258
-
268
+ """
269
+ Runs a Python script within the sandbox workspace.
270
+
271
+ Args:
272
+ script_code: Python code to execute
273
+ timeout: Optional timeout override (uses self.timeout if None)
274
+
275
+ Returns:
276
+ ExecutionResult with stdout, stderr, success status, etc.
277
+ """
278
+ # Optionally inject matplotlib non-interactive backend
279
+ # This is only done if auto_matplotlib=True (used by Web UI for visualization)
280
+ if self.auto_matplotlib:
281
+ # Force non-interactive backend for matplotlib to prevent blocking plt.show()
282
+ fixed_code = "import matplotlib\nmatplotlib.use('Agg')\n" + script_code
283
+ logger.debug("Auto-injected matplotlib non-interactive backend")
284
+ else:
285
+ # Use code as-is without modification (default for DSLighting package)
286
+ fixed_code = script_code
287
+
259
288
  script_name = f"_sandbox_script_{uuid.uuid4().hex}.py"
260
289
  script_path = self.workspace.run_dir / script_name
261
290
  execution_id = uuid.uuid4().hex
@@ -26,7 +26,7 @@ Advanced Usage:
26
26
  For more information, see: https://github.com/usail-hkust/dslighting
27
27
  """
28
28
 
29
- __version__ = "1.3.1"
29
+ __version__ = "1.3.6"
30
30
  __author__ = "DSLighting Team"
31
31
 
32
32
  # Core API classes
@@ -60,7 +60,7 @@ def load_data(source, **kwargs):
60
60
  return loader.load(source, **kwargs)
61
61
 
62
62
 
63
- def run_agent(data=None, task_id=None, data_dir=None, **kwargs):
63
+ def run_agent(data=None, task_id=None, data_dir=None, keep_workspace=False, keep_workspace_on_failure=True, **kwargs):
64
64
  """
65
65
  Quick one-liner: load data and run with defaults.
66
66
 
@@ -70,6 +70,8 @@ def run_agent(data=None, task_id=None, data_dir=None, **kwargs):
70
70
  data: Optional data source (path, DataFrame, dict, etc.)
71
71
  task_id: Task/Competition identifier (e.g., "bike-sharing-demand")
72
72
  data_dir: Base data directory (default: "data/competitions")
73
+ keep_workspace: Keep workspace after completion (default: False)
74
+ keep_workspace_on_failure: Keep workspace on failure (default: True)
73
75
  **kwargs: Parameters passed to Agent.__init__ and Agent.run
74
76
 
75
77
  Returns:
@@ -90,7 +92,8 @@ def run_agent(data=None, task_id=None, data_dir=None, **kwargs):
90
92
  >>> result = dslighting.run_agent(
91
93
  ... task_id="bike-sharing-demand",
92
94
  ... workflow="autokaggle",
93
- ... model="gpt-4o"
95
+ ... model="gpt-4o",
96
+ ... keep_workspace=True # Keep workspace for debugging
94
97
  ... )
95
98
  """
96
99
  # Extract run-specific parameters if present
@@ -112,6 +115,10 @@ def run_agent(data=None, task_id=None, data_dir=None, **kwargs):
112
115
  if data_dir is not None:
113
116
  run_kwargs['data_dir'] = data_dir
114
117
 
118
+ # Add workspace preservation parameters to agent
119
+ agent_params['keep_workspace'] = keep_workspace
120
+ agent_params['keep_workspace_on_failure'] = keep_workspace_on_failure
121
+
115
122
  # Create agent and run
116
123
  agent = Agent(**agent_params)
117
124
  return agent.run(data, **run_kwargs)
@@ -108,6 +108,8 @@ class Agent:
108
108
  num_drafts: int = None,
109
109
  workspace_dir: str = None,
110
110
  run_name: str = None,
111
+ keep_workspace: bool = False,
112
+ keep_workspace_on_failure: bool = True,
111
113
  verbose: bool = True,
112
114
  **kwargs
113
115
  ):
@@ -129,6 +131,8 @@ class Agent:
129
131
  num_drafts: Number of drafts to generate
130
132
  workspace_dir: Custom workspace directory
131
133
  run_name: Name for this run
134
+ keep_workspace: Keep workspace after completion (default: False)
135
+ keep_workspace_on_failure: Keep workspace on failure (default: True)
132
136
  verbose: Enable verbose logging
133
137
  **kwargs: Additional parameters passed to DSATConfig
134
138
  """
@@ -148,6 +152,8 @@ class Agent:
148
152
  num_drafts=num_drafts,
149
153
  workspace_dir=workspace_dir,
150
154
  run_name=run_name,
155
+ keep_workspace=keep_workspace,
156
+ keep_workspace_on_failure=keep_workspace_on_failure,
151
157
  **kwargs
152
158
  )
153
159
 
@@ -60,6 +60,8 @@ class ConfigBuilder:
60
60
  num_drafts: int = None,
61
61
  workspace_dir: str = None,
62
62
  run_name: str = None,
63
+ keep_workspace: bool = None,
64
+ keep_workspace_on_failure: bool = None,
63
65
  **kwargs
64
66
  ) -> DSATConfig:
65
67
  """
@@ -76,6 +78,8 @@ class ConfigBuilder:
76
78
  num_drafts: Number of drafts to generate
77
79
  workspace_dir: Workspace directory
78
80
  run_name: Name for this run
81
+ keep_workspace: Keep workspace after completion
82
+ keep_workspace_on_failure: Keep workspace on failure
79
83
  **kwargs: Additional parameters
80
84
 
81
85
  Returns:
@@ -100,6 +104,8 @@ class ConfigBuilder:
100
104
  num_drafts=num_drafts,
101
105
  workspace_dir=workspace_dir,
102
106
  run_name=run_name,
107
+ keep_workspace=keep_workspace,
108
+ keep_workspace_on_failure=keep_workspace_on_failure,
103
109
  **kwargs
104
110
  )
105
111
  config = self._deep_merge(config, user_config)
@@ -180,7 +186,22 @@ class ConfigBuilder:
180
186
  logger.warning("LLM_MODEL_CONFIGS must be a JSON object")
181
187
  return {}
182
188
 
183
- return {k: v for k, v in parsed.items() if isinstance(k, str) and isinstance(v, dict)}
189
+ # Process each model config
190
+ result = {}
191
+ for k, v in parsed.items():
192
+ if not isinstance(k, str) or not isinstance(v, dict):
193
+ continue
194
+
195
+ # Handle api_key as list (take the first one)
196
+ if "api_key" in v and isinstance(v["api_key"], list):
197
+ if len(v["api_key"]) > 0:
198
+ v = v.copy() # Shallow copy to avoid mutating original
199
+ v["api_key"] = v["api_key"][0]
200
+ logger.debug(f"Model '{k}': using first API key from list of {len(v['api_key'])}")
201
+
202
+ result[k] = v
203
+
204
+ return result
184
205
 
185
206
  def _build_user_config(
186
207
  self,
@@ -194,6 +215,8 @@ class ConfigBuilder:
194
215
  num_drafts: int = None,
195
216
  workspace_dir: str = None,
196
217
  run_name: str = None,
218
+ keep_workspace: bool = None,
219
+ keep_workspace_on_failure: bool = None,
197
220
  **kwargs
198
221
  ) -> Dict[str, Any]:
199
222
  """Build user configuration from parameters."""
@@ -230,6 +253,12 @@ class ConfigBuilder:
230
253
  if workspace_dir is not None:
231
254
  config.setdefault("run", {}).setdefault("parameters", {})["workspace_dir"] = workspace_dir
232
255
 
256
+ if keep_workspace is not None:
257
+ config.setdefault("run", {})["keep_all_workspaces"] = keep_workspace
258
+
259
+ if keep_workspace_on_failure is not None:
260
+ config.setdefault("run", {})["keep_workspace_on_failure"] = keep_workspace_on_failure
261
+
233
262
  # Additional kwargs are added to run.parameters
234
263
  if kwargs:
235
264
  config.setdefault("run", {}).setdefault("parameters", {}).update(kwargs)
@@ -297,13 +297,45 @@ class DataLoader:
297
297
  pass
298
298
  else:
299
299
  self.logger.warning(f"Path does not exist: {path}")
300
- # Still use the path even if it doesn't exist (might be created later)
301
- if path.is_dir() or not path.suffix:
300
+
301
+ # Try to find the data in common locations
302
+ competition_id = path.name
303
+
304
+ # Common search locations for data
305
+ search_locations = [
306
+ # Current project: ./data/competitions/
307
+ Path.cwd() / "data" / "competitions" / competition_id,
308
+ # Parent dslighting: ../dslighting/data/competitions/
309
+ Path.cwd().parent / "dslighting" / "data" / "competitions" / competition_id,
310
+ # Parent data: ../data/competitions/
311
+ Path.cwd().parent / "data" / "competitions" / competition_id,
312
+ # From package location: ../../data/competitions/
313
+ Path(__file__).parent.parent.parent / "data" / "competitions" / competition_id,
314
+ # Absolute path fallback
315
+ Path("/Users/liufan/Applications/Github/dslighting/data/competitions") / competition_id,
316
+ ]
317
+
318
+ for location in search_locations:
319
+ self.logger.info(f" Trying: {location}")
320
+ if location.exists() and location.is_dir():
321
+ data_dir = location
322
+ self.logger.info(f" ✓ Found data at: {data_dir}")
323
+ break
324
+
325
+ if data_dir is None:
326
+ # Last resort: use the original resolved path
327
+ self.logger.warning(f" Could not find data, using original path: {path}")
302
328
  data_dir = path
303
- self.logger.info(f"Using non-existent path as data directory: {data_dir}")
304
- else:
305
- data_dir = path.parent
306
- self.logger.info(f"Using parent of non-existent file: {data_dir}")
329
+
330
+ # Try to load description (if data_dir was found)
331
+ if data_dir and data_dir.exists():
332
+ desc_file = data_dir / "description.md"
333
+ if desc_file.exists():
334
+ try:
335
+ description = desc_file.read_text(encoding='utf-8')
336
+ self.logger.info(f"Loaded description from {desc_file}")
337
+ except Exception:
338
+ pass
307
339
 
308
340
  # Create MLE-style detection
309
341
  from dslighting.utils.defaults import WORKFLOW_RECOMMENDATIONS
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dslighting
3
- Version: 1.3.1
3
+ Version: 1.3.6
4
4
  Summary: Simplified API for Data Science Agent Automation
5
5
  Author: DSLighting Team
6
6
  License: AGPL-3.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dslighting"
7
- version = "1.3.1"
7
+ version = "1.3.6"
8
8
  description = "Simplified API for Data Science Agent Automation"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
File without changes
File without changes
File without changes
File without changes
File without changes