clarifai 11.1.7rc2__py3-none-any.whl → 11.1.7rc3__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.
clarifai/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "11.1.7rc2"
1
+ __version__ = "11.1.7rc3"
@@ -135,6 +135,7 @@ class ModelClient:
135
135
  # set names, annotations and docstrings
136
136
  f.__name__ = method_name
137
137
  f.__qualname__ = f'{self.__class__.__name__}.{method_name}'
138
+ # TODO: set signature from annotations to the function, currently MethodSignature don't have `annotations_json` field
138
139
  # input_annotations = json.loads(method_signature.annotations_json)
139
140
  # return_annotation = input_annotations.pop('return', None)
140
141
  # sig = inspect.signature(f).replace(
@@ -44,9 +44,6 @@ ENV PYTHONPATH=${PYTHONPATH}:/home/nonroot/main \
44
44
  CLARIFAI_COMPUTE_CLUSTER_ID=${CLARIFAI_COMPUTE_CLUSTER_ID} \
45
45
  CLARIFAI_API_BASE=${CLARIFAI_API_BASE:-https://api.clarifai.com}
46
46
 
47
- # # Write out the model function signatures
48
- # RUN ["python", "-m", "clarifai.cli", "model", "signatures", "--model_path", "/home/nonroot/main", "--out_path", "/home/nonroot/main/signatures.yaml"]
49
-
50
47
  # Finally run the clarifai entrypoint to start the runner loop and local dev server.
51
48
  # Note(zeiler): we may want to make this a clarifai CLI call.
52
49
  ENTRYPOINT ["python", "-m", "clarifai.runners.server"]
@@ -1,3 +1,4 @@
1
+ import builtins
1
2
  import importlib
2
3
  import inspect
3
4
  import os
@@ -6,6 +7,7 @@ import sys
6
7
  import tarfile
7
8
  import time
8
9
  from string import Template
10
+ from unittest.mock import MagicMock
9
11
 
10
12
  import yaml
11
13
  from clarifai_grpc.grpc.api import resources_pb2, service_pb2
@@ -80,7 +82,7 @@ class ModelBuilder:
80
82
 
81
83
  def load_model_class(self):
82
84
  """
83
- Import the model class from the model.py file.
85
+ Import the model class from the model.py file, dynamically handling missing dependencies
84
86
  """
85
87
  # look for default model.py file location
86
88
  for loc in ["model.py", "1/model.py"]:
@@ -95,7 +97,29 @@ class ModelBuilder:
95
97
  spec = importlib.util.spec_from_file_location(module_name, model_file)
96
98
  module = importlib.util.module_from_spec(spec)
97
99
  sys.modules[module_name] = module
98
- spec.loader.exec_module(module)
100
+
101
+ original_import = builtins.__import__
102
+
103
+ def custom_import(name, globals=None, locals=None, fromlist=(), level=0):
104
+
105
+ # Allow standard libraries and clarifai
106
+ if self._is_standard_or_clarifai(name):
107
+ return original_import(name, globals, locals, fromlist, level)
108
+
109
+ # Mock all third-party imports to avoid ImportErrors or other issues
110
+ return MagicMock()
111
+
112
+ # Replace the built-in __import__ function with our custom one
113
+ builtins.__import__ = custom_import
114
+
115
+ try:
116
+ spec.loader.exec_module(module)
117
+ except Exception as e:
118
+ logger.error(f"Error loading model.py: {e}")
119
+ raise
120
+ finally:
121
+ # Restore the original __import__ function
122
+ builtins.__import__ = original_import
99
123
 
100
124
  # Find all classes in the model.py file that are subclasses of ModelClass
101
125
  classes = [
@@ -122,6 +146,23 @@ class ModelBuilder:
122
146
  model_class = classes[0]
123
147
  return model_class
124
148
 
149
+ def _is_standard_or_clarifai(self, name):
150
+ """Check if import is from standard library or clarifai"""
151
+ if name.startswith("clarifai"):
152
+ return True
153
+
154
+ # Handle Python <3.10 compatibility
155
+ stdlib_names = getattr(sys, "stdlib_module_names", sys.builtin_module_names)
156
+ if name in stdlib_names:
157
+ return True
158
+
159
+ # Handle submodules (e.g., os.path)
160
+ parts = name.split(".")
161
+ for i in range(1, len(parts)):
162
+ if ".".join(parts[:i]) in stdlib_names:
163
+ return True
164
+ return False
165
+
125
166
  def _validate_folder(self, folder):
126
167
  if folder == ".":
127
168
  folder = "" # will getcwd() next which ends with /
@@ -557,13 +598,12 @@ class ModelBuilder:
557
598
  logger.info(f"Updated config.yaml with {len(concepts)} concepts.")
558
599
 
559
600
  def get_model_version_proto(self):
560
-
601
+ signatures = self.get_method_signatures()
561
602
  model_version_proto = resources_pb2.ModelVersion(
562
603
  pretrained_model_config=resources_pb2.PretrainedModelConfig(),
563
604
  inference_compute_info=self.inference_compute_info,
605
+ method_signatures=signatures,
564
606
  )
565
- # TODO: update this to `model_signatures` field when it's available in the API
566
- model_version_proto.model_signature.extend(self.get_method_signatures())
567
607
 
568
608
  model_type_id = self.config.get('model').get('model_type_id')
569
609
  if model_type_id in CONCEPTS_REQUIRED_MODEL_TYPE:
@@ -750,6 +790,7 @@ class ModelBuilder:
750
790
  model_id=self.model_proto.id,
751
791
  version_id=self.model_version_id,
752
792
  ))
793
+
753
794
  status_code = resp.model_version.status.code
754
795
  logs = self.get_model_build_logs()
755
796
  for log_entry in logs.log_entries:
@@ -8,6 +8,7 @@ from typing import Any, Dict, Iterator, List
8
8
 
9
9
  from clarifai_grpc.grpc.api import resources_pb2, service_pb2
10
10
  from clarifai_grpc.grpc.api.status import status_code_pb2, status_pb2
11
+ from google.protobuf import json_format
11
12
 
12
13
  from clarifai.runners.utils import data_types
13
14
  from clarifai.runners.utils.method_signatures import (build_function_signature, deserialize,
@@ -84,6 +85,7 @@ class ModelClass(ABC):
84
85
  try:
85
86
  # TODO add method name field to proto
86
87
  method_name = 'predict'
88
+ inference_params = get_inference_params(request)
87
89
  if len(request.inputs) > 0 and '_method_name' in request.inputs[0].data.metadata:
88
90
  method_name = request.inputs[0].data.metadata['_method_name']
89
91
  if method_name == '_GET_SIGNATURES': # special case to fetch signatures, TODO add endpoint for this
@@ -94,8 +96,8 @@ class ModelClass(ABC):
94
96
  method_info = method._cf_method_info
95
97
  signature = method_info.signature
96
98
  python_param_types = method_info.python_param_types
97
- inputs = self._convert_input_protos_to_python(request.inputs, signature.input_fields,
98
- python_param_types)
99
+ inputs = self._convert_input_protos_to_python(request.inputs, inference_params,
100
+ signature.input_fields, python_param_types)
99
101
  if len(inputs) == 1:
100
102
  inputs = inputs[0]
101
103
  output = method(**inputs)
@@ -121,6 +123,7 @@ class ModelClass(ABC):
121
123
  ) -> Iterator[service_pb2.MultiOutputResponse]:
122
124
  try:
123
125
  method_name = 'generate'
126
+ inference_params = get_inference_params(request)
124
127
  if len(request.inputs) > 0 and '_method_name' in request.inputs[0].data.metadata:
125
128
  method_name = request.inputs[0].data.metadata['_method_name']
126
129
  method = getattr(self, method_name)
@@ -128,8 +131,8 @@ class ModelClass(ABC):
128
131
  signature = method_info.signature
129
132
  python_param_types = method_info.python_param_types
130
133
 
131
- inputs = self._convert_input_protos_to_python(request.inputs, signature.input_fields,
132
- python_param_types)
134
+ inputs = self._convert_input_protos_to_python(request.inputs, inference_params,
135
+ signature.input_fields, python_param_types)
133
136
  if len(inputs) == 1:
134
137
  inputs = inputs[0]
135
138
  for output in method(**inputs):
@@ -161,6 +164,7 @@ class ModelClass(ABC):
161
164
  assert len(request.inputs) == 1, "Streaming requires exactly one input"
162
165
 
163
166
  method_name = 'generate'
167
+ inference_params = get_inference_params(request)
164
168
  if len(request.inputs) > 0 and '_method_name' in request.inputs[0].data.metadata:
165
169
  method_name = request.inputs[0].data.metadata['_method_name']
166
170
  method = getattr(self, method_name)
@@ -175,8 +179,8 @@ class ModelClass(ABC):
175
179
  stream_argname = stream_sig.name
176
180
 
177
181
  # convert all inputs for the first request, including the first stream value
178
- inputs = self._convert_input_protos_to_python(request.inputs, signature.input_fields,
179
- python_param_types)
182
+ inputs = self._convert_input_protos_to_python(request.inputs, inference_params,
183
+ signature.input_fields, python_param_types)
180
184
  kwargs = inputs[0]
181
185
 
182
186
  # first streaming item
@@ -187,8 +191,8 @@ class ModelClass(ABC):
187
191
  yield first_item
188
192
  # subsequent streaming items contain only the streaming input
189
193
  for request in request_iterator:
190
- item = self._convert_input_protos_to_python(request.inputs, [stream_sig],
191
- python_param_types)
194
+ item = self._convert_input_protos_to_python(request.inputs, inference_params,
195
+ [stream_sig], python_param_types)
192
196
  item = item[0][stream_argname]
193
197
  yield item
194
198
 
@@ -210,11 +214,12 @@ class ModelClass(ABC):
210
214
  stack_trace=traceback.format_exc().split('\n')))
211
215
 
212
216
  def _convert_input_protos_to_python(self, inputs: List[resources_pb2.Input],
217
+ inference_params: dict,
213
218
  variables_signature: List[resources_pb2.ModelTypeField],
214
219
  python_param_types) -> List[Dict[str, Any]]:
215
220
  result = []
216
221
  for input in inputs:
217
- kwargs = deserialize(input.data, variables_signature)
222
+ kwargs = deserialize(input.data, variables_signature, inference_params)
218
223
  # dynamic cast to annotated types
219
224
  for k, v in kwargs.items():
220
225
  if k not in python_param_types:
@@ -262,6 +267,18 @@ class ModelClass(ABC):
262
267
  return method_info
263
268
 
264
269
 
270
+ # Helper function to get the inference params
271
+ def get_inference_params(request) -> dict:
272
+ """Get the inference params from the request."""
273
+ inference_params = {}
274
+ if request.model.model_version.id != "":
275
+ output_info = request.model.model_version.output_info
276
+ output_info = json_format.MessageToDict(output_info, preserving_proto_field_name=True)
277
+ if "params" in output_info:
278
+ inference_params = output_info["params"]
279
+ return inference_params
280
+
281
+
265
282
  class _MethodInfo:
266
283
 
267
284
  def __init__(self, method):
@@ -260,7 +260,7 @@ def serialize(kwargs, signatures, proto=None, is_output=False):
260
260
  return proto
261
261
 
262
262
 
263
- def deserialize(proto, signatures, is_output=False):
263
+ def deserialize(proto, signatures, inference_params={}, is_output=False):
264
264
  '''
265
265
  Deserialize the given proto into kwargs using the given signatures.
266
266
  '''
@@ -271,7 +271,12 @@ def deserialize(proto, signatures, is_output=False):
271
271
  for sig_i, sig in enumerate(signatures):
272
272
  serializer = serializer_from_signature(sig)
273
273
  part = parts_by_name.get(sig.name)
274
- if part is None:
274
+ inference_params_value = inference_params.get(sig.name)
275
+ if part is not None:
276
+ kwargs[sig.name] = serializer.deserialize(part.data)
277
+ elif inference_params_value is not None:
278
+ kwargs[sig.name] = inference_params_value
279
+ else:
275
280
  if sig_i == 0:
276
281
  # possible inlined first value
277
282
  value = serializer.deserialize(proto)
@@ -280,10 +285,10 @@ def deserialize(proto, signatures, is_output=False):
280
285
  # an actual zero value passed in must be set in an explicit part
281
286
  kwargs[sig.name] = value
282
287
  continue
288
+
283
289
  if sig.required or is_output: # TODO allow optional outputs?
284
290
  raise ValueError(f'Missing required field: {sig.name}')
285
291
  continue
286
- kwargs[sig.name] = serializer.deserialize(part.data)
287
292
  if len(kwargs) == 1 and 'return' in kwargs:
288
293
  return kwargs['return']
289
294
  return kwargs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: clarifai
3
- Version: 11.1.7rc2
3
+ Version: 11.1.7rc3
4
4
  Summary: Clarifai Python SDK
5
5
  Home-page: https://github.com/Clarifai/clarifai-python
6
6
  Author: Clarifai
@@ -20,8 +20,8 @@ Classifier: Operating System :: OS Independent
20
20
  Requires-Python: >=3.8
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
- Requires-Dist: clarifai-grpc>=11.1.3
24
- Requires-Dist: clarifai-protocol>=0.0.16
23
+ Requires-Dist: clarifai-grpc>=11.2.4
24
+ Requires-Dist: clarifai-protocol>=0.0.20
25
25
  Requires-Dist: numpy>=1.22.0
26
26
  Requires-Dist: tqdm>=4.65.0
27
27
  Requires-Dist: rich>=13.4.2
@@ -1,4 +1,4 @@
1
- clarifai/__init__.py,sha256=wdUgSsqM2z4GI0P61jMvu6qis3DRIZLxpNZx-WIA-A4,26
1
+ clarifai/__init__.py,sha256=l0wL8EO4WdUNsKcblugjv356bjDqdfj1fg33DYBM7Uo,26
2
2
  clarifai/cli.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  clarifai/errors.py,sha256=RwzTajwds51wLD0MVlMC5kcpBnzRpreDLlazPSBZxrg,2605
4
4
  clarifai/versions.py,sha256=jctnczzfGk_S3EnVqb2FjRKfSREkNmvNEwAAa_VoKiQ,222
@@ -31,7 +31,7 @@ clarifai/client/deployment.py,sha256=w7Y6pA1rYG4KRK1SwusRZc2sQRXlG8wezuVdzSWpCo0
31
31
  clarifai/client/input.py,sha256=obMAHMDU1OwfXZ8KraOnGFlWzlW-3F7Ob_2lcOQMlhY,46339
32
32
  clarifai/client/lister.py,sha256=03KGMvs5RVyYqxLsSrWhNc34I8kiF1Ph0NeyEwu7nMU,2082
33
33
  clarifai/client/model.py,sha256=DFlZLIExMUvYXc9hDzVLYka6_AbfG3vqLlhZkk4GfIY,76835
34
- clarifai/client/model_client.py,sha256=JCHawIxxJvPMAD3W-gmVKz6_XQDP1shoxFYaZCEN1X8,16943
34
+ clarifai/client/model_client.py,sha256=aeKx8mx5gXqkRnipHLDYRPLIy28c0iO2MWCn3dRK9eE,17068
35
35
  clarifai/client/module.py,sha256=FTkm8s9m-EaTKN7g9MnLhGJ9eETUfKG7aWZ3o1RshYs,4204
36
36
  clarifai/client/nodepool.py,sha256=la3vTFrO4LX8zm2eQ5jqf2L0-kQ63Dano8FibadoZbk,10152
37
37
  clarifai/client/search.py,sha256=GaPWN6JmTQGZaCHr6U1yv0zqR6wKFl7i9IVLg2ul1CI,14254
@@ -135,11 +135,11 @@ clarifai/runners/__pycache__/__init__.cpython-39.pyc,sha256=-nXCOCynrtendkWHFkfy
135
135
  clarifai/runners/dockerfile_template/Dockerfile.cpu.template,sha256=WD9B_gpTZ8mzWPQXtWWr5Bp_TEhVJzbznKVIjyPK8yk,1136
136
136
  clarifai/runners/dockerfile_template/Dockerfile.cuda.template,sha256=LAn7H1zi_lyk5iQdGdNifQrwrTifAZe9FHgxPCYg8D0,1464
137
137
  clarifai/runners/dockerfile_template/Dockerfile.nim,sha256=CSdUAehj3uOwminioLnT5v3hIXzkkv3sgx9RT4k5Lks,2806
138
- clarifai/runners/dockerfile_template/Dockerfile.template,sha256=NRybJOAOCtnIec-CyxQDG-vqdSLrPV_MEFFHmEv_9tc,2509
138
+ clarifai/runners/dockerfile_template/Dockerfile.template,sha256=5cjv7U8PmWa3DB_5B1CqSYh_6GE0E0np52TIAa7EIDE,2312
139
139
  clarifai/runners/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
140
140
  clarifai/runners/models/base_typed_model.py,sha256=0QCWxch8CcyJSKvE1D4PILd2RSnQZHTmx4DXlQQ6dpo,7856
141
- clarifai/runners/models/model_builder.py,sha256=cMS6P8II9FCtGmlz9A89NmogdDdjmjYbQf5JbJn_tFw,33538
142
- clarifai/runners/models/model_class.py,sha256=llFJhIhA8unzvROryma2_dmzoZNduN7Ki5AOLzGdCLA,11034
141
+ clarifai/runners/models/model_builder.py,sha256=p4xl3Hvol7J25Z8E--CWvrPQr1SxWuchvwZC3Dx18l0,34777
142
+ clarifai/runners/models/model_class.py,sha256=qK5qk4geoFpqrRtl4VmKK90CIJKyWmD_vjJMqLWR_CQ,11854
143
143
  clarifai/runners/models/model_class_refract.py,sha256=HxuozxSW7ag5yWCPxjNwgLArQ6dORhyGXlnpPaZz2-c,3211
144
144
  clarifai/runners/models/model_run_locally.py,sha256=VZetm9Mko8MBjcjwr6PCnTU9gF3glgD5qvpbj-8tW2s,17962
145
145
  clarifai/runners/models/model_runner.py,sha256=qyc73pe4xc9BsUKHwnOyC9g-RNCARiFis4GTh-yg0vg,6219
@@ -163,7 +163,7 @@ clarifai/runners/utils/data_types.py,sha256=nJS9n4oQHcwf2scxH8pl5TjHcY9l6ZdY401f
163
163
  clarifai/runners/utils/data_utils.py,sha256=R1iQ82TuQ9JwxCJk8yEB1Lyb0BYVhVbWJI9YDi1zGOs,318
164
164
  clarifai/runners/utils/loader.py,sha256=SgNHMwRmCCymFQm8aDp73NmIUHhM-N60CBlTKbPzmVc,7470
165
165
  clarifai/runners/utils/logger.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
166
- clarifai/runners/utils/method_signatures.py,sha256=nVrxqD9rHxUzFYK-RSmX-D6uhw0nP_pVkFfIQ9IMEaM,17224
166
+ clarifai/runners/utils/method_signatures.py,sha256=EnVdLsyh7GzE7pY7fWqtcDN6t6gYKnGLU_yJnHxw7vI,17415
167
167
  clarifai/runners/utils/serializers.py,sha256=S4sRsOVvH191vAGTRTAAdwLlQwlK4T5QVRDGPptg9nQ,7191
168
168
  clarifai/runners/utils/url_fetcher.py,sha256=v_8JOWmkyFAzsBulsieKX7Nfjy1Yg7wGSZeqfEvw2cg,1640
169
169
  clarifai/runners/utils/__pycache__/__init__.cpython-310.pyc,sha256=0GGbXIecXlOZmQKMCkSRhEBY_a1zvoimv-mHG4pJuNA,167
@@ -229,9 +229,9 @@ clarifai/workflows/__pycache__/__init__.cpython-39.pyc,sha256=9nA--jULSW7OFrYOcs
229
229
  clarifai/workflows/__pycache__/export.cpython-310.pyc,sha256=phEGwi2gAojCUhRTqjZVeTDn7Gk6LCVBeSTjAj4m9iY,2418
230
230
  clarifai/workflows/__pycache__/utils.cpython-310.pyc,sha256=M9_KTM7GOOS5SPrWwAzqHDqyGvgKi3xuSGvyw6MNf-I,1925
231
231
  clarifai/workflows/__pycache__/validate.cpython-310.pyc,sha256=c18Jgp_-CAm8RD_tmUpDCPoqZeexaoWELG0yBzb9rjw,2149
232
- clarifai-11.1.7rc2.dist-info/LICENSE,sha256=mUqF_d12-qE2n41g7C5_sq-BMLOcj6CNN-jevr15YHU,555
233
- clarifai-11.1.7rc2.dist-info/METADATA,sha256=OnchJXRxSSzZ62JYttF3CYL9AS5IVJ-sxoD-5JBLYnw,22214
234
- clarifai-11.1.7rc2.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
235
- clarifai-11.1.7rc2.dist-info/entry_points.txt,sha256=X9FZ4Z-i_r2Ud1RpZ9sNIFYuu_-9fogzCMCRUD9hyX0,51
236
- clarifai-11.1.7rc2.dist-info/top_level.txt,sha256=wUMdCQGjkxaynZ6nZ9FAnvBUCgp5RJUVFSy2j-KYo0s,9
237
- clarifai-11.1.7rc2.dist-info/RECORD,,
232
+ clarifai-11.1.7rc3.dist-info/LICENSE,sha256=mUqF_d12-qE2n41g7C5_sq-BMLOcj6CNN-jevr15YHU,555
233
+ clarifai-11.1.7rc3.dist-info/METADATA,sha256=-t2evkzC5WdrGOlmiBDkINx4r8Pnpg-q7ZEvqz6RgMk,22214
234
+ clarifai-11.1.7rc3.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
235
+ clarifai-11.1.7rc3.dist-info/entry_points.txt,sha256=X9FZ4Z-i_r2Ud1RpZ9sNIFYuu_-9fogzCMCRUD9hyX0,51
236
+ clarifai-11.1.7rc3.dist-info/top_level.txt,sha256=wUMdCQGjkxaynZ6nZ9FAnvBUCgp5RJUVFSy2j-KYo0s,9
237
+ clarifai-11.1.7rc3.dist-info/RECORD,,