DeepFabric 4.8.1__py3-none-any.whl → 4.8.2__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.
@@ -2,13 +2,13 @@ import json
2
2
  import logging
3
3
  import sys
4
4
 
5
+ from functools import cached_property
5
6
  from typing import Any
6
7
 
7
- import torch
8
-
9
8
  from transformers import AutoConfig, AutoModelForCausalLM, AutoTokenizer
10
9
 
11
10
  from ...schemas import ToolDefinition
11
+ from ...utils import import_optional_dependency
12
12
  from ..inference import InferenceBackend, InferenceConfig, ModelResponse
13
13
  from .tool_call_parsers import ToolCallParser, get_parser
14
14
 
@@ -29,6 +29,30 @@ logger = logging.getLogger(__name__)
29
29
  class TransformersBackend(InferenceBackend):
30
30
  """Inference backend using HuggingFace Transformers."""
31
31
 
32
+ @cached_property
33
+ def _torch(self) -> Any:
34
+ """Dynamically import 'torch' and verify its availability.
35
+
36
+ Returns:
37
+ The imported torch module.
38
+
39
+ Raises:
40
+ ModuleNotFoundError: If 'torch' is not installed in the environment.
41
+ """
42
+ return import_optional_dependency("torch", "training")
43
+
44
+ @cached_property
45
+ def _peft(self) -> Any:
46
+ """Dynamically import 'peft' and verify its availability.
47
+
48
+ Returns:
49
+ The imported peft module.
50
+
51
+ Raises:
52
+ ModuleNotFoundError: If 'peft' is not installed in the environment.
53
+ """
54
+ return import_optional_dependency("peft", "training")
55
+
32
56
  def __init__(self, config: InferenceConfig):
33
57
  """Initialize Transformers backend.
34
58
 
@@ -47,22 +71,22 @@ class TransformersBackend(InferenceBackend):
47
71
  # Get device from pre-loaded model
48
72
  self.device = str(next(config.model.parameters()).device)
49
73
  # Auto-detect best available device
50
- elif torch.cuda.is_available():
74
+ elif self._torch.cuda.is_available():
51
75
  self.device = "cuda"
52
- elif torch.backends.mps.is_available():
76
+ elif self._torch.backends.mps.is_available():
53
77
  self.device = "mps"
54
78
  else:
55
79
  self.device = "cpu"
56
80
 
57
81
  # Determine dtype based on device
58
82
  if self.device == "cuda" or self.device.startswith("cuda:"):
59
- dtype = torch.float16
83
+ dtype = self._torch.float16
60
84
  device_map = "auto"
61
85
  elif self.device == "mps":
62
- dtype = torch.float32 # MPS works best with float32
86
+ dtype = self._torch.float32 # MPS works best with float32
63
87
  device_map = None
64
88
  else:
65
- dtype = torch.float32
89
+ dtype = self._torch.float32
66
90
  device_map = None
67
91
 
68
92
  # Handle pre-loaded model case - skip all loading logic
@@ -138,9 +162,9 @@ class TransformersBackend(InferenceBackend):
138
162
  load_in_4bit=config.load_in_4bit,
139
163
  )
140
164
  # Load LoRA adapter using PEFT
141
- from peft import PeftModel # noqa: PLC0415
142
-
143
- self.model = PeftModel.from_pretrained(self.model, config.adapter_path)
165
+ self.model = self._peft.PeftModel.from_pretrained(
166
+ self.model, config.adapter_path
167
+ )
144
168
  else:
145
169
  # Load merged model or base model directly
146
170
  self.model, self.tokenizer = FastLanguageModel.from_pretrained(
@@ -172,9 +196,7 @@ class TransformersBackend(InferenceBackend):
172
196
 
173
197
  # Load PEFT adapter if provided
174
198
  if config.adapter_path:
175
- from peft import PeftModel # noqa: PLC0415
176
-
177
- self.model = PeftModel.from_pretrained(self.model, config.adapter_path)
199
+ self.model = self._peft.PeftModel.from_pretrained(self.model, config.adapter_path)
178
200
 
179
201
  # Move to device if not using device_map
180
202
  if self.device in ("cpu", "mps"):
@@ -217,7 +239,7 @@ class TransformersBackend(InferenceBackend):
217
239
  ).to(self.model.device)
218
240
 
219
241
  # Generate with optimizations
220
- with torch.no_grad():
242
+ with self._torch.no_grad():
221
243
  outputs = self.model.generate(
222
244
  **inputs,
223
245
  max_new_tokens=self.config.max_tokens,
@@ -273,7 +295,7 @@ class TransformersBackend(InferenceBackend):
273
295
  ).to(self.model.device)
274
296
 
275
297
  # Generate batch with optimizations
276
- with torch.no_grad():
298
+ with self._torch.no_grad():
277
299
  outputs = self.model.generate(
278
300
  **inputs,
279
301
  max_new_tokens=self.config.max_tokens,
@@ -316,8 +338,8 @@ class TransformersBackend(InferenceBackend):
316
338
  del self.model
317
339
  if hasattr(self, "tokenizer"):
318
340
  del self.tokenizer
319
- if torch.cuda.is_available():
320
- torch.cuda.empty_cache()
341
+ if self._torch.cuda.is_available():
342
+ self._torch.cuda.empty_cache()
321
343
 
322
344
  def _format_prompt(
323
345
  self,
deepfabric/schemas.py CHANGED
@@ -136,7 +136,7 @@ class MCPInputSchemaProperty(BaseModel):
136
136
 
137
137
  model_config = {"extra": "allow"}
138
138
 
139
- type: str = Field(default="string", description="JSON Schema type")
139
+ type: str | list[str] = Field(default="string", description="JSON Schema type (string or array for nullable)")
140
140
  description: str = Field(default="", description="Property description")
141
141
  default: Any | None = Field(default=None, description="Default value")
142
142
 
@@ -159,7 +159,7 @@ class MCPToolDefinition(BaseModel):
159
159
  See: https://modelcontextprotocol.io/specification/2025-06-18/schema#tool
160
160
  """
161
161
 
162
- model_config = {"extra": "allow"}
162
+ model_config = {"extra": "allow", "populate_by_name": True}
163
163
 
164
164
  name: str = Field(description="Tool name")
165
165
  description: str = Field(default="", description="Tool description")
@@ -367,7 +367,15 @@ class ToolDefinition(BaseModel):
367
367
  required_params = set(input_schema.required)
368
368
 
369
369
  for param_name, param_props in input_schema.properties.items():
370
- df_type = type_mapping.get(param_props.type, "str")
370
+ # Handle type as either string or array (for nullable types like ["string", "null"])
371
+ param_type = param_props.type
372
+ if isinstance(param_type, list):
373
+ # Extract the primary type (non-null type from array)
374
+ primary_type = next((t for t in param_type if t != "null"), "string")
375
+ else:
376
+ primary_type = param_type
377
+
378
+ df_type = type_mapping.get(primary_type, "str")
371
379
  default_str = str(param_props.default) if param_props.default is not None else ""
372
380
 
373
381
  parameters.append(
deepfabric/utils.py CHANGED
@@ -1,9 +1,12 @@
1
1
  import ast
2
2
  import asyncio
3
+ import importlib
3
4
  import json
4
5
  import os
5
6
  import re
6
7
 
8
+ from typing import Any
9
+
7
10
  VALIDATION_ERROR_INDICATORS = [
8
11
  "validation error",
9
12
  "value error",
@@ -162,3 +165,33 @@ def get_bool_env(key: str, default: bool = False) -> bool:
162
165
  if val is None:
163
166
  return default
164
167
  return val.lower() in ("1", "true", "yes", "on")
168
+
169
+
170
+ def import_optional_dependency(
171
+ module_name: str,
172
+ extra: str | None = None,
173
+ ) -> Any:
174
+ """
175
+ Import an optional dependency at runtime.
176
+
177
+ Args:
178
+ module_name (str): The name of the module to import.
179
+ extra (str | None): The optional dependency group providing this module.
180
+
181
+ Returns:
182
+ Any: The imported module.
183
+
184
+ Raises:
185
+ ModuleNotFoundError: If the module is not installed.
186
+ """
187
+ try:
188
+ return importlib.import_module(module_name)
189
+ except ModuleNotFoundError:
190
+ if extra:
191
+ msg = (
192
+ f"The '{module_name}' library is required for the '{extra}' features. "
193
+ f"Please install it using: pip install 'deepfabric[{extra}]'"
194
+ )
195
+ else:
196
+ msg = f"The '{module_name}' library is required but is not installed."
197
+ raise ModuleNotFoundError(msg) from None
@@ -1,11 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DeepFabric
3
- Version: 4.8.1
3
+ Version: 4.8.2
4
4
  Summary: Curate High Quality Datasets, Train, Evaluate and Ship
5
5
  Author-email: DeepFabric Team <oss@alwaysfurther.ai>
6
6
  License-File: LICENSE
7
7
  Requires-Python: >=3.10
8
- Requires-Dist: accelerate>=0.20.0
9
8
  Requires-Dist: anthropic>=0.75.0
10
9
  Requires-Dist: click>=8.1.7
11
10
  Requires-Dist: componentize-py>=0.19.3
@@ -19,7 +18,6 @@ Requires-Dist: ollama>=0.6.1
19
18
  Requires-Dist: openai>=1.107.2
20
19
  Requires-Dist: outlines==1.2.9
21
20
  Requires-Dist: packaging>=25.0
22
- Requires-Dist: peft>=0.7.0
23
21
  Requires-Dist: posthog>=3.0.0
24
22
  Requires-Dist: protobuf>=3.20.0
25
23
  Requires-Dist: pydantic>=2.0.0
@@ -27,9 +25,7 @@ Requires-Dist: pyyaml>=6.0.1
27
25
  Requires-Dist: rich>=13.0.0
28
26
  Requires-Dist: sentencepiece>=0.1.99
29
27
  Requires-Dist: spin-sdk>=3.4.1
30
- Requires-Dist: torch>=2.4.0
31
28
  Requires-Dist: transformers>=4.57.1
32
- Requires-Dist: trl>=0.26.2
33
29
  Provides-Extra: dev
34
30
  Requires-Dist: bandit>=1.7.10; extra == 'dev'
35
31
  Requires-Dist: mermaid-py>=0.2.0; extra == 'dev'
@@ -42,6 +38,11 @@ Requires-Dist: ruff>=0.1.0; extra == 'dev'
42
38
  Provides-Extra: docs
43
39
  Requires-Dist: mkdocs-material>=9.0.0; extra == 'docs'
44
40
  Requires-Dist: mkdocstrings[python]>=0.30.0; extra == 'docs'
41
+ Provides-Extra: training
42
+ Requires-Dist: accelerate>=0.20.0; extra == 'training'
43
+ Requires-Dist: peft>=0.7.0; extra == 'training'
44
+ Requires-Dist: torch>=2.4.0; extra == 'training'
45
+ Requires-Dist: trl>=0.26.2; extra == 'training'
45
46
  Description-Content-Type: text/markdown
46
47
 
47
48
  <div align="center">
@@ -21,14 +21,14 @@ deepfabric/loader.py,sha256=YNTGZZE-POjR0BIlx6WCT4bIzf0T4lW_fQl7ev9UFqE,18584
21
21
  deepfabric/metrics.py,sha256=iwtNHBX4ZTYUg2FZgtFcG3U0e9RlV2c1cm1Kp34FeWU,6129
22
22
  deepfabric/progress.py,sha256=3XQQrf2pUZlyd-8eRcNATH1v0Oi8JMedVHGbhPcca-8,9354
23
23
  deepfabric/prompts.py,sha256=JVFMeeBa2qqOMvmP_xx8bWzZ6ot9eyqOP3u8XzzPx3g,10290
24
- deepfabric/schemas.py,sha256=ckzAjDc6IlC8Y-Pi2hyYRqcSwARX7z_GELuCypXuSgI,37401
24
+ deepfabric/schemas.py,sha256=r8qQuu19o9ev0JNxcChjbpWym9m5WLItyxw8szYLSjI,37867
25
25
  deepfabric/stream_simulator.py,sha256=GzvAxWxHVsuTwgXlqwXNfrTUDn6sND2kJOoQuYg88FA,3028
26
26
  deepfabric/topic_manager.py,sha256=6YxMO6dQHaGyxghsI8iNJGP1miaekBe5Mh1WdYeLqdI,11164
27
27
  deepfabric/topic_model.py,sha256=i_wYpw2kUl8NLodOSaqNu-C4_d6caYT1kPe_vkKjoyw,707
28
28
  deepfabric/tree.py,sha256=Kxl2iLHU55xPq2MwdoLM0-M2nZRx51bRj9FM36jqs-M,14933
29
29
  deepfabric/tui.py,sha256=9ETtGFQk26U9PQ2b5foplVYDKxaFGd-8UqK7uSKyHwE,50480
30
30
  deepfabric/update_checker.py,sha256=AUa9iUdkGNzu7tWkQRxIlF19YRmKLetwxu-Ys2ONS8Y,5145
31
- deepfabric/utils.py,sha256=ve6tku_-jgW_ZIkh9osUEQ3C_03J6R_zOw0Xf5UGJYc,4891
31
+ deepfabric/utils.py,sha256=a9G6VTw52UdddTFoMw-JjunjawtPN54N275-XGPL2cQ,5822
32
32
  deepfabric/validation.py,sha256=1x1X_45kyI0w_FCdUiNdvy4LQu3B0KVR-fyvLkrKEGw,5125
33
33
  deepfabric/evaluation/__init__.py,sha256=7xMLmYXaNC1U7qf88S9fMxWTABoDRiOcimSYfCt_PSo,1224
34
34
  deepfabric/evaluation/evaluator.py,sha256=qNowle5v2ukDJ11igNOCParlBfXT8QUeOvXx6sSJ_Ug,34480
@@ -39,7 +39,7 @@ deepfabric/evaluation/backends/__init__.py,sha256=GqC0FfpWmtgJmjHd0kVKNg7g-NjhRo
39
39
  deepfabric/evaluation/backends/llm_eval_backend.py,sha256=4jp5tnTp7v_0pHCGhcPbI55ig79-eVxdzooesi2PymA,18827
40
40
  deepfabric/evaluation/backends/ollama_backend.py,sha256=mtPp1JtIDRjb76X_rTa1jS1ETzMjte8t3WJjuYV1oDQ,4372
41
41
  deepfabric/evaluation/backends/tool_call_parsers.py,sha256=Ufg4Xt3mrDS-WbGor6tOOr4xZNCHk3Co2C-z_o-pAkM,14126
42
- deepfabric/evaluation/backends/transformers_backend.py,sha256=WcqB9gkayQpjx2Em00lhzJg8RcWdQEYbctDNXLzFChA,14484
42
+ deepfabric/evaluation/backends/transformers_backend.py,sha256=f3rbFxjWdv2NhDvlMfl0YwFUkfh0i5dlM3JKYeoJgvQ,15243
43
43
  deepfabric/evaluation/evaluators/__init__.py,sha256=NdH65YvanskRGe6r7JepkTNGGt8xA-GLugagU3VQ_WM,353
44
44
  deepfabric/evaluation/evaluators/base.py,sha256=1TiLr-_oF9dRmdSgJs94dDbf0gTwRS8TGGz2C1Z3nag,2946
45
45
  deepfabric/evaluation/evaluators/registry.py,sha256=VGeb1AHFGkn9TLpcqfuGIZi1jgh7Qw0NNILT6z3Se6M,2171
@@ -69,8 +69,8 @@ deepfabric/training/api_key_prompt.py,sha256=pSIMX3eDGyV9x_r7MHE4TyIsIB2SqYb8gKC
69
69
  deepfabric/training/callback.py,sha256=5zdifbHA2PWILHl2cVFyO65aW7cGAQhcvDqm3s8_I0Q,13221
70
70
  deepfabric/training/dataset_utils.py,sha256=klx8DoawEwuMigBDP-RpMAfe7FvYxRbhj599MErxBr4,7313
71
71
  deepfabric/training/metrics_sender.py,sha256=ZCyvMv5hRu8XJnQYVGXJ9wh7HEMJ0l3Ktyi8_etOpZs,10833
72
- deepfabric-4.8.1.dist-info/METADATA,sha256=rqINWAsjSFRqf4__rva0qMmWFq9cNtSxK1zhndl5anI,20427
73
- deepfabric-4.8.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
74
- deepfabric-4.8.1.dist-info/entry_points.txt,sha256=zatevils13hfs8x29_vmUyivQ6rTtq7hE2RBusZw1Fo,50
75
- deepfabric-4.8.1.dist-info/licenses/LICENSE,sha256=-qRt8wmrhQ9aMf7KhmZXc2vrTETYZF-6_T1KCeUhvHY,11340
76
- deepfabric-4.8.1.dist-info/RECORD,,
72
+ deepfabric-4.8.2.dist-info/METADATA,sha256=15ZBOITSr6pigZYD-GBn_IwRlnzftZ64hwrXldKr1mg,20536
73
+ deepfabric-4.8.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
74
+ deepfabric-4.8.2.dist-info/entry_points.txt,sha256=zatevils13hfs8x29_vmUyivQ6rTtq7hE2RBusZw1Fo,50
75
+ deepfabric-4.8.2.dist-info/licenses/LICENSE,sha256=-qRt8wmrhQ9aMf7KhmZXc2vrTETYZF-6_T1KCeUhvHY,11340
76
+ deepfabric-4.8.2.dist-info/RECORD,,