clarifai-grpc 6.4.0__py3-none-any.whl → 11.10.3__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.
Files changed (50) hide show
  1. clarifai_grpc/__init__.py +33 -0
  2. clarifai_grpc/channel/clarifai_channel.py +150 -44
  3. clarifai_grpc/channel/custom_converters/custom_dict_to_message.py +41 -34
  4. clarifai_grpc/channel/custom_converters/custom_message_to_dict.py +85 -74
  5. clarifai_grpc/channel/errors.py +5 -0
  6. clarifai_grpc/channel/exceptions.py +1 -1
  7. clarifai_grpc/channel/grpc_json_channel.py +387 -261
  8. clarifai_grpc/channel/http_client.py +125 -104
  9. clarifai_grpc/grpc/api/resources_pb2.py +984 -7266
  10. clarifai_grpc/grpc/api/resources_pb2.pyi +17925 -0
  11. clarifai_grpc/grpc/api/resources_pb2_grpc.py +1 -0
  12. clarifai_grpc/grpc/api/service_pb2.py +1578 -8672
  13. clarifai_grpc/grpc/api/service_pb2.pyi +18269 -0
  14. clarifai_grpc/grpc/api/service_pb2_grpc.py +9746 -1859
  15. clarifai_grpc/grpc/api/status/status_code_pb2.py +33 -1334
  16. clarifai_grpc/grpc/api/status/status_code_pb2.pyi +1210 -0
  17. clarifai_grpc/grpc/api/status/status_code_pb2_grpc.py +1 -0
  18. clarifai_grpc/grpc/api/status/status_pb2.py +23 -149
  19. clarifai_grpc/grpc/api/status/status_pb2.pyi +174 -0
  20. clarifai_grpc/grpc/api/status/status_pb2_grpc.py +1 -0
  21. clarifai_grpc/grpc/api/utils/extensions_pb2.py +13 -46
  22. clarifai_grpc/grpc/api/utils/extensions_pb2.pyi +39 -0
  23. clarifai_grpc/grpc/api/utils/extensions_pb2_grpc.py +1 -0
  24. clarifai_grpc/grpc/api/utils/matrix_pb2.py +26 -0
  25. clarifai_grpc/grpc/api/utils/matrix_pb2.pyi +53 -0
  26. clarifai_grpc/grpc/api/utils/matrix_pb2_grpc.py +4 -0
  27. clarifai_grpc/grpc/api/utils/test_proto_pb2.py +17 -158
  28. clarifai_grpc/grpc/api/utils/test_proto_pb2.pyi +107 -0
  29. clarifai_grpc/grpc/api/utils/test_proto_pb2_grpc.py +1 -0
  30. clarifai_grpc/grpc/auth/scope/scope_pb2.py +245 -448
  31. clarifai_grpc/grpc/auth/scope/scope_pb2.pyi +550 -0
  32. clarifai_grpc/grpc/auth/scope/scope_pb2_grpc.py +1 -0
  33. clarifai_grpc/grpc/auth/types/types_pb2.py +11 -62
  34. clarifai_grpc/grpc/auth/types/types_pb2.pyi +78 -0
  35. clarifai_grpc/grpc/auth/types/types_pb2_grpc.py +1 -0
  36. clarifai_grpc/grpc/auth/util/extension_pb2.py +14 -68
  37. clarifai_grpc/grpc/auth/util/extension_pb2.pyi +68 -0
  38. clarifai_grpc/grpc/auth/util/extension_pb2_grpc.py +1 -0
  39. clarifai_grpc-11.10.3.dist-info/METADATA +124 -0
  40. clarifai_grpc-11.10.3.dist-info/RECORD +53 -0
  41. {clarifai_grpc-6.4.0.dist-info → clarifai_grpc-11.10.3.dist-info}/WHEEL +1 -1
  42. {clarifai_grpc-6.4.0.dist-info → clarifai_grpc-11.10.3.dist-info}/top_level.txt +0 -2
  43. clarifai_grpc-6.4.0.dist-info/METADATA +0 -88
  44. clarifai_grpc-6.4.0.dist-info/RECORD +0 -46
  45. scripts/__init__.py +0 -0
  46. scripts/app_and_key_for_tests.py +0 -180
  47. tests/__init__.py +0 -0
  48. tests/helpers.py +0 -105
  49. tests/test_integration.py +0 -243
  50. {clarifai_grpc-6.4.0.dist-info → clarifai_grpc-11.10.3.dist-info/licenses}/LICENSE +0 -0
@@ -3,294 +3,420 @@ import logging
3
3
  import re
4
4
  import typing # noqa
5
5
 
6
- import requests # noqa
7
6
  from google.protobuf.descriptor import Descriptor # noqa
8
7
  from google.protobuf.message import Message # noqa
9
8
 
10
9
  from clarifai_grpc.channel import http_client
11
10
  from clarifai_grpc.channel.custom_converters.custom_dict_to_message import dict_to_protobuf
12
11
  from clarifai_grpc.channel.custom_converters.custom_message_to_dict import protobuf_to_dict
13
- from clarifai_grpc.channel.errors import UsageError
12
+ from clarifai_grpc.channel.errors import NotImplementedCaller, UsageError
13
+ from clarifai_grpc.channel.exceptions import ClarifaiException
14
14
  from clarifai_grpc.grpc.api.service_pb2 import _V2
15
15
 
16
-
17
16
  BASE_URL = "https://api.clarifai.com"
18
- URL_TEMPLATE_PARAM_REGEX = re.compile(r'\{{1}(.*?)\}{1}')
17
+ URL_TEMPLATE_PARAM_REGEX = re.compile(r"\{{1}(.*?)\}{1}")
19
18
 
20
- logger = logging.getLogger('clarifai')
19
+ logger = logging.getLogger("clarifai")
21
20
 
22
21
 
23
22
  class GRPCJSONChannel(object):
24
- """ This mimics the behaviour of a grpc channel object but allows transport over https with
25
- json request and response bodies.
26
-
27
- Currently there is only support for unary_unary requests. If you have any other type of grpc
28
- request this channel will nicely fail when trying to use within a grpc stub.
29
-
30
- Example:
31
- Assuming your top level endpoints are called V2 and in a proto/clarifai/api/endpoint.proto file,
32
- then you build those in python and can import the spec to use in GRPCJSONChannel as follows:
33
-
34
- from clarifai.rest.grpc.proto.clarifai.api.endpoint_pb2_grpc import V2Stub
35
- from clarifai.rest.grpc.proto.clarifai.api.endpoint_pb2 import _V2
36
- channel = GRPCJSONChannel(key="api key", service_descriptor=_V2)
37
- stub = V2Stub(channel)
38
-
39
- # Then you can use the stub to call just like grpc directly!!!
40
- result = stub.PostInputs(PostInputsRequest(inputs=[Input(data=Data(image=Image(
41
- url="http://...")))]))
42
- """
43
-
44
- def __init__(
45
- self,
46
- session: requests.Session,
47
- base_url: str = BASE_URL,
48
- service_descriptor: typing.Any = _V2
49
- ) -> None:
50
- """
51
- Args:
52
- session: a request session
53
- base_url: if you want to point at a different url than the default.
54
- service_descriptor: This is a ServiceDescriptor object found in the compiled grpc-gateway
55
- .proto results. For example if your proto defining the endpoints is in endpoint.proto then look
56
- in endpoint_pb2.py file for ServiceDescriptor and use that.
57
- """
58
- self.session = session
59
- self.name_to_resources = {}
60
-
61
- for m in service_descriptor.methods:
62
- # This gets the google.api.http object from the .proto file that looks like this:
63
- # option (google.api.http) = {
64
- # delete: "/v2/users/{user_app_id.user_id}/apps/{user_app_id.app_id}/models/{model_id}"
65
- # additional_bindings {
66
- # delete: "/v2/models/{model_id}"
67
- # }
68
- # Then we check if there are additional_bindings and use that if so (because we've had the
69
- # convention of having the default urls in there and the not yet used urls at the top level.
70
-
71
- for field in m.GetOptions().ListFields():
72
- if field[0].name == "http":
73
- base_http_rule = field[1]
74
- break
75
- else:
76
- raise Exception("Method %s has no 'http' field" % m.full_name)
77
-
78
- protobuf_name = '/' + service_descriptor.full_name + '/' + m.name
79
- self.name_to_resources[protobuf_name] = (m.input_type, [])
80
-
81
- for http_rule in base_http_rule.additional_bindings or [base_http_rule]:
82
- # Get the url template and the method to use for http.
83
- if http_rule.HasField('get'):
84
- method = 'GET'
85
- url_template = base_url + http_rule.get
86
- elif http_rule.HasField('post'):
87
- method = 'POST'
88
- url_template = base_url + http_rule.post
89
- elif http_rule.HasField('patch'):
90
- method = 'PATCH'
91
- url_template = base_url + http_rule.patch
92
- elif http_rule.HasField('put'):
93
- method = 'PUT'
94
- url_template = base_url + http_rule.put
95
- elif http_rule.HasField('delete'):
96
- method = 'DELETE'
97
- url_template = base_url + http_rule.delete
98
- else:
99
- raise Exception("Failed to parse the grpc-gateway service spec.")
100
-
101
- self.name_to_resources[protobuf_name][1].append((url_template, method))
102
-
103
- def unary_unary(self, name, request_serializer, response_deserializer):
104
- # type: (str, typing.Callable, typing.Callable) -> JSONUnaryUnary
105
- """ Method to create the callable JSONUnaryUnary. """
106
- request_message_descriptor, resources = self.name_to_resources[name]
107
- return JSONUnaryUnary(self.session, request_message_descriptor, resources, request_serializer,
108
- response_deserializer)
109
-
110
-
111
- class JSONUnaryUnary(object):
112
- """ This mimics the unary_unary calls and is actually the thing doing the http requests.
113
- """
114
-
115
- def __init__(
116
- self,
117
- session, # type: requests.Session
118
- request_message_descriptor, # type: Descriptor
119
- resources, # type: typing.List[typing.Tuple[str, typing.Any]]
120
- request_serializer, # type: typing.Callable
121
- response_deserializer # type: typing.Callable
122
- ):
123
- # type: (...) -> None
124
- """
125
- Args:
126
- session: a request session
127
- request_message_descriptor: this is a MessageDescriptor for the input type.
128
- resources: a list of available resource endpoints
129
- request_serializer: the method to use to serialize the request proto
130
- response_deserializer: the response proto deserializer which will be used to convert the http
131
- response will be parsed into this.
23
+ """This mimics the behaviour of a grpc channel object but allows transport over https with
24
+ json request and response bodies.
132
25
 
133
- Returns:
134
- response: a proto object of class response_deserializer filled in with the response.
135
- """
136
- self.session = session
137
- self.request_message_descriptor = request_message_descriptor
138
- self.resources = resources
139
- self.request_serializer = request_serializer
140
- self.response_deserializer = response_deserializer
26
+ Currently there is only support for unary_unary requests. If you have any other type of grpc
27
+ request this channel will nicely fail when trying to use within a grpc stub.
141
28
 
142
- def __call__(self, request, metadata=None): # type: (Message, tuple) -> Message
143
- """ This is where the actually calls come through when the stub is called such as
144
- stub.PostInputs(). They get passed to this method which actually makes the request.
29
+ Example:
30
+ Assuming your top level endpoints are called V2 and in a proto/clarifai/api/endpoint.proto file,
31
+ then you build those in python and can import the spec to use in GRPCJSONChannel as follows:
145
32
 
146
- Args:
147
- request: the proto object for the request. It must be the proper type for the request or the
148
- server will complain. Note: this doesn't type check the incoming request in the client but
149
- does make sure it can serialize before sending to the server atleast.
150
- metadata: the authorization string (either API key or Personal Access Token)
33
+ from clarifai.rest.grpc.proto.clarifai.api.endpoint_pb2_grpc import V2Stub
34
+ from clarifai.rest.grpc.proto.clarifai.api.endpoint_pb2 import _V2
35
+ channel = GRPCJSONChannel(key="api key", service_descriptor=_V2)
36
+ stub = V2Stub(channel)
151
37
 
152
- Returns:
153
- response: the proto object that this method returns.
38
+ # Then you can use the stub to call just like grpc directly!!!
39
+ result = stub.PostInputs(PostInputsRequest(inputs=[Input(data=Data(image=Image(
40
+ url="http://...")))]))
154
41
  """
155
- # if metadata is not None:
156
- # raise Exception("No support currently for metadata field.")
157
-
158
- # There is no __self__ attribute on the request_serializer unfortunately.
159
- expected_object_name = self.request_message_descriptor.name
160
- if type(request).__name__ != expected_object_name:
161
- raise Exception("The input request must be of type: %s from %s" %
162
- (expected_object_name, self.request_message_descriptor.file.name))
163
-
164
- params = protobuf_to_dict(request, use_integers_for_enums=False, ignore_show_empty=True)
165
-
166
- url, method, url_fields = _pick_proper_endpoint(self.resources, params)
167
42
 
168
- for url_field in url_fields:
169
- if url_field in params:
170
- del params[url_field]
43
+ def __init__(
44
+ self,
45
+ session, # type: requests.Session,
46
+ base_url: str = BASE_URL,
47
+ service_descriptor: typing.Any = _V2,
48
+ ) -> None:
49
+ """
50
+ Args:
51
+ session: a request session
52
+ base_url: if you want to point at a different url than the default.
53
+ service_descriptor: This is a ServiceDescriptor object found in the compiled grpc-gateway
54
+ .proto results. For example if your proto defining the endpoints is in endpoint.proto then look
55
+ in endpoint_pb2.py file for ServiceDescriptor and use that.
56
+ """
57
+ self.session = session
58
+ self.name_to_resources = {}
59
+
60
+ for m in service_descriptor.methods:
61
+ # This gets the google.api.http object from the .proto file that looks like this:
62
+ # option (google.api.http) = {
63
+ # delete: "/v2/users/{user_app_id.user_id}/apps/{user_app_id.app_id}/models/{model_id}"
64
+ # additional_bindings {
65
+ # delete: "/v2/models/{model_id}"
66
+ # }
67
+ # Then we check if there are additional_bindings and use that if so (because we've had the
68
+ # convention of having the default urls in there and the not yet used urls at the top level.
69
+
70
+ for field in m.GetOptions().ListFields():
71
+ if field[0].name == "http":
72
+ base_http_rule = field[1]
73
+ break
74
+ else:
75
+ raise Exception("Method %s has no 'http' field" % m.full_name)
76
+
77
+ protobuf_name = "/" + service_descriptor.full_name + "/" + m.name
78
+ self.name_to_resources[protobuf_name] = (m.input_type, [])
79
+
80
+ def register_bindings(http_rule):
81
+ # Get the url template and the method to use for http.
82
+ if http_rule.HasField("get"):
83
+ method = "GET"
84
+ url_template = base_url + http_rule.get
85
+ elif http_rule.HasField("post"):
86
+ method = "POST"
87
+ url_template = base_url + http_rule.post
88
+ elif http_rule.HasField("patch"):
89
+ method = "PATCH"
90
+ url_template = base_url + http_rule.patch
91
+ elif http_rule.HasField("put"):
92
+ method = "PUT"
93
+ url_template = base_url + http_rule.put
94
+ elif http_rule.HasField("delete"):
95
+ method = "DELETE"
96
+ url_template = base_url + http_rule.delete
97
+ else:
98
+ raise Exception("Failed to parse the grpc-gateway service spec.")
99
+
100
+ self.name_to_resources[protobuf_name][1].append((url_template, method))
101
+
102
+ register_bindings(base_http_rule)
103
+ for http_rule in base_http_rule.additional_bindings:
104
+ register_bindings(http_rule)
105
+
106
+ def unary_unary(self, name, request_serializer, response_deserializer):
107
+ # type: (str, typing.Callable, typing.Callable) -> JSONUnaryUnary
108
+ """Method to create the callable JSONUnaryUnary."""
109
+ request_message_descriptor, resources = self.name_to_resources[name]
110
+ return JSONUnaryUnary(
111
+ self.session,
112
+ request_message_descriptor,
113
+ resources,
114
+ request_serializer,
115
+ response_deserializer,
116
+ )
117
+
118
+ def unary_stream(self, method, request_serializer=None, response_deserializer=None):
119
+ return NotImplementedCaller()
120
+
121
+ def stream_stream(self, name, request_serializer, response_deserializer):
122
+ # type: (str, typing.Callable, typing.Callable) -> JSONStreamStream
123
+ """Method to create the callable JSONStreamStream."""
124
+ request_message_descriptor, resources = self.name_to_resources[name]
125
+ return JSONStreamStream(
126
+ self.session,
127
+ request_message_descriptor,
128
+ resources,
129
+ request_serializer,
130
+ response_deserializer,
131
+ )
132
+
133
+ def stream_unary(self, method, request_serializer=None, response_deserializer=None):
134
+ return NotImplementedCaller()
171
135
 
172
- auth_string = self._read_auth_string(metadata)
173
136
 
174
- http = http_client.HttpClient(self.session, auth_string)
175
- response_json = http.execute_request(method, params, url)
176
-
177
- # Get the actual message object to construct
178
- message = self.response_deserializer
179
- result = dict_to_protobuf(message, response_json, ignore_unknown_fields=True)
180
-
181
- return result
182
-
183
- def _read_auth_string(self, metadata: typing.Tuple) -> str:
184
- """
185
- The auth string returned is either an API key or a PAT (Personal Access Token).
186
- :param metadata: The call metadata.
187
- :return: The auth string.
188
- """
189
-
190
- authorization_values = [v for k, v in metadata if k.lower() == "authorization"]
191
- if (
192
- len(authorization_values) != 1 or
193
- not authorization_values[0].startswith("Key ") or
194
- len(authorization_values[0].split(" ")) != 2
137
+ class JSONUnaryUnary(object):
138
+ """This mimics the unary_unary calls and is actually the thing doing the http requests."""
139
+
140
+ def __init__(
141
+ self,
142
+ session, # type: requests.Session
143
+ request_message_descriptor, # type: Descriptor
144
+ resources, # type: typing.List[typing.Tuple[str, typing.Any]]
145
+ request_serializer, # type: typing.Callable
146
+ response_deserializer, # type: typing.Callable
147
+ ):
148
+ # type: (...) -> None
149
+ """
150
+ Args:
151
+ session: a request session
152
+ request_message_descriptor: this is a MessageDescriptor for the input type.
153
+ resources: a list of available resource endpoints
154
+ request_serializer: the method to use to serialize the request proto
155
+ response_deserializer: the response proto deserializer which will be used to convert the http
156
+ response will be parsed into this.
157
+
158
+ Returns:
159
+ response: a proto object of class response_deserializer filled in with the response.
160
+ """
161
+ self.session = session
162
+ self.request_message_descriptor = request_message_descriptor
163
+ self.resources = resources
164
+ self.request_serializer = request_serializer
165
+ self.response_deserializer = response_deserializer
166
+
167
+ def __call__(self, request, metadata=None): # type: (Message, tuple) -> Message
168
+ """This is where the actually calls come through when the stub is called such as
169
+ stub.PostInputs(). They get passed to this method which actually makes the request.
170
+
171
+ Args:
172
+ request: the proto object for the request. It must be the proper type for the request or the
173
+ server will complain. Note: this doesn't type check the incoming request in the client but
174
+ does make sure it can serialize before sending to the server atleast.
175
+ metadata: the authorization string (either API key or Personal Access Token)
176
+
177
+ Returns:
178
+ response: the proto object that this method returns.
179
+ """
180
+ # if metadata is not None:
181
+ # raise Exception("No support currently for metadata field.")
182
+
183
+ # There is no __self__ attribute on the request_serializer unfortunately.
184
+ expected_object_name = self.request_message_descriptor.name
185
+ if type(request).__name__ != expected_object_name:
186
+ raise Exception(
187
+ "The input request must be of type: %s from %s"
188
+ % (expected_object_name, self.request_message_descriptor.file.name)
189
+ )
190
+
191
+ params = protobuf_to_dict(request, use_integers_for_enums=False, ignore_show_empty=True)
192
+
193
+ url, method, url_fields = _pick_proper_endpoint(self.resources, params)
194
+
195
+ for url_field in url_fields:
196
+ if url_field in params:
197
+ del params[url_field]
198
+
199
+ auth_string = self._read_auth_string(metadata)
200
+
201
+ http = http_client.HttpClient(self.session, auth_string)
202
+ response_json = http.execute_request(method, params, url)
203
+
204
+ # Get the actual message object to construct
205
+ message = self.response_deserializer
206
+ result = dict_to_protobuf(message, response_json, ignore_unknown_fields=True)
207
+
208
+ return result
209
+
210
+ def _read_auth_string(self, metadata: typing.Tuple) -> str:
211
+ """
212
+ The auth string returned is either an API key or a PAT (Personal Access Token).
213
+ :param metadata: The call metadata.
214
+ :return: The auth string.
215
+ """
216
+
217
+ authorization_values = [v for k, v in metadata if k.lower() == "authorization"]
218
+ if (
219
+ len(authorization_values) != 1
220
+ or not authorization_values[0].startswith("Key ")
221
+ or len(authorization_values[0].split(" ")) != 2
222
+ ):
223
+ raise UsageError(
224
+ "Please provide metadata with the format of "
225
+ "(('authorization', 'Key YOUR_CLARIFAI_API_KEY'),)"
226
+ )
227
+ api_key = authorization_values[0].split(" ")[1]
228
+ return api_key
229
+
230
+
231
+ class JSONStreamStream(object):
232
+ """This mimics the stream_stream calls and is actually the thing doing the http requests."""
233
+
234
+ def __init__(
235
+ self,
236
+ session, # type: requests.Session
237
+ request_message_descriptor, # type: Descriptor
238
+ resources, # type: typing.List[typing.Tuple[str, typing.Any]]
239
+ request_serializer, # type: typing.Callable
240
+ response_deserializer, # type: typing.Callable
195
241
  ):
196
- raise UsageError("Please provide metadata with the format of "
197
- "(('authorization', 'Key YOUR_CLARIFAI_API_KEY'),)")
198
- api_key = authorization_values[0].split(" ")[1]
199
- return api_key
242
+ # type: (...) -> None
243
+ """
244
+ Args:
245
+ session: a request session
246
+ request_message_descriptor: this is a MessageDescriptor for the input type.
247
+ resources: a list of available resource endpoints
248
+ request_serializer: the method to use to serialize the request proto
249
+ response_deserializer: the response proto deserializer which will be used to convert the http
250
+ response will be parsed into this.
251
+
252
+ Returns:
253
+ response: a proto object of class response_deserializer filled in with the response.
254
+ """
255
+ self.session = session
256
+ self.request_message_descriptor = request_message_descriptor
257
+ self.resources = resources
258
+ self.request_serializer = request_serializer
259
+ self.response_deserializer = response_deserializer
260
+
261
+ def __call__(self, request, metadata=None): # type: (Message, tuple) -> Message
262
+ """This is where the actually calls come through when the stub is called such as
263
+ stub.PostInputs(). They get passed to this method which actually makes the request.
264
+
265
+ Args:
266
+ request: the proto object for the request. It must be the proper type for the request or the
267
+ server will complain. Note: this doesn't type check the incoming request in the client but
268
+ does make sure it can serialize before sending to the server atleast.
269
+ metadata: the authorization string (either API key or Personal Access Token)
270
+
271
+ Returns:
272
+ response: the proto object that this method returns.
273
+ """
274
+ # if metadata is not None:
275
+ # raise Exception("No support currently for metadata field.")
276
+
277
+ # There is no __self__ attribute on the request_serializer unfortunately.
278
+ expected_object_name = self.request_message_descriptor.name
279
+ if type(request).__name__ != expected_object_name:
280
+ raise Exception(
281
+ "The input request must be of type: %s from %s"
282
+ % (expected_object_name, self.request_message_descriptor.file.name)
283
+ )
284
+
285
+ params = protobuf_to_dict(request, use_integers_for_enums=False, ignore_show_empty=True)
286
+
287
+ url, method, url_fields = _pick_proper_endpoint(self.resources, params)
288
+
289
+ for url_field in url_fields:
290
+ if url_field in params:
291
+ del params[url_field]
292
+
293
+ auth_string = self._read_auth_string(metadata)
294
+
295
+ http = http_client.HttpClient(self.session, auth_string)
296
+ response_json = http.execute_request(method, params, url)
297
+
298
+ # Get the actual message object to construct
299
+ message = self.response_deserializer
300
+ result = dict_to_protobuf(message, response_json, ignore_unknown_fields=True)
301
+
302
+ return result
303
+
304
+ def _read_auth_string(self, metadata: typing.Tuple) -> str:
305
+ """
306
+ The auth string returned is either an API key or a PAT (Personal Access Token).
307
+ :param metadata: The call metadata.
308
+ :return: The auth string.
309
+ """
310
+
311
+ authorization_values = [v for k, v in metadata if k.lower() == "authorization"]
312
+ if (
313
+ len(authorization_values) != 1
314
+ or not authorization_values[0].startswith("Key ")
315
+ or len(authorization_values[0].split(" ")) != 2
316
+ ):
317
+ raise UsageError(
318
+ "Please provide metadata with the format of "
319
+ "(('authorization', 'Key YOUR_CLARIFAI_API_KEY'),)"
320
+ )
321
+ api_key = authorization_values[0].split(" ")[1]
322
+ return api_key
200
323
 
201
324
 
202
325
  def _read_app_info(data):
203
- """
204
- This function extracts the app_id and user_id values from the request object, or returns None.
205
- :param data: The request object
206
- :return: (app_id, user_id) or None
207
- """
208
- if type(data) is list:
209
- for e in data:
210
- vals = _read_app_info(e)
211
- if vals:
212
- return vals
213
- elif type(data) is dict:
214
- for k, v in data.items():
215
- if k == "apps":
216
- if len(v) == 1:
217
- return v[0]["id"], v[0]["user_id"]
218
- elif len(v) == 0:
219
- return None
220
- else:
221
- raise
222
- elif k == "metadata":
223
- continue
224
- vals = _read_app_info(v)
225
- if vals:
226
- return vals
227
- return None
326
+ """
327
+ This function extracts the app_id and user_id values from the request object, or returns None.
328
+ :param data: The request object
329
+ :return: (app_id, user_id) or None
330
+ """
331
+ if type(data) is list:
332
+ for e in data:
333
+ vals = _read_app_info(e)
334
+ if vals:
335
+ return vals
336
+ elif type(data) is dict:
337
+ for k, v in data.items():
338
+ if k == "user_app_id":
339
+ return v.get("app_id", ""), v.get("user_id", "me")
340
+ elif k == "apps":
341
+ if len(v) == 1:
342
+ return v[0]["id"], v[0].get("user_id", "me")
343
+ elif len(v) == 0:
344
+ return None
345
+ else:
346
+ raise ClarifaiException("Only one app has to be specified")
347
+ elif k == "metadata":
348
+ continue
349
+ vals = _read_app_info(v)
350
+ if vals:
351
+ return vals
352
+ return None
228
353
 
229
354
 
230
355
  def _pick_proper_endpoint(
231
356
  resources, # type: typing.List[typing.Tuple[str, typing.Any]]
232
- request_dict # type: dict
357
+ request_dict, # type: dict
233
358
  ):
234
- # type: (...) -> typing.Tuple[str, typing.Any, typing.List[str]]
235
- """
236
- Fills in the url template with the actual url params from the request body.
237
- Picks the most appropriate url depending on which parameters are present in the request body.
238
- Args:
239
- resources: all available resource endpoints for this method.
240
- request_dict: a dictionary form of the request from json_format.MessageToDict(request,
241
- preserving_proto_field_name=True) so that we can recursively lookup url params.
242
- Returns:
243
- url: the url string to use in requests.
244
- method: one of get/post/patch/delete.
245
- """
246
-
247
- best_match_url = None
248
- best_match_method = None
249
- best_match_count = -1
250
-
251
- ids = _read_app_info(request_dict)
252
- app_id, user_id = ids if ids else (None, None)
253
-
254
- all_fields = []
255
- best_match_url_fields = None
256
- for url_template, method in resources:
257
- all_arguments_translated = True
258
-
259
- url = url_template
260
- count = 0
261
- url_fields = list(re.findall(URL_TEMPLATE_PARAM_REGEX, url_template))
262
- for field in url_fields:
263
- field_name = field.split('.')[-1]
264
-
265
- if field_name == "app_id":
266
- field_value = app_id
267
- elif field_name == "user_id":
268
- if user_id:
269
- field_value = user_id
270
- else:
271
- # "me" is the alias for the ID of the authorized user.
272
- field_value = "me"
273
- else:
274
- field_value = request_dict.get(field_name)
275
- if not field_value:
276
- all_arguments_translated = False
277
- break
278
-
279
- count += 1
280
-
281
- url = url.replace('{' + field + '}', field_value)
282
-
283
- all_fields.extend(url_fields)
284
-
285
- if all_arguments_translated:
286
- if best_match_count < count:
287
- best_match_url = url
288
- best_match_url_fields = url_fields
289
- best_match_method = method
290
- best_match_count = count
291
-
292
- if not best_match_url:
293
- raise Exception("You must set one case of the following fields in your request proto: "
294
- "%s" % all_fields)
295
-
296
- return best_match_url, best_match_method, best_match_url_fields
359
+ # type: (...) -> typing.Tuple[str, typing.Any, typing.List[str]]
360
+ """
361
+ Fills in the url template with the actual url params from the request body.
362
+ Picks the most appropriate url depending on which parameters are present in the request body.
363
+ Args:
364
+ resources: all available resource endpoints for this method.
365
+ request_dict: a dictionary form of the request from json_format.MessageToDict(request,
366
+ preserving_proto_field_name=True) so that we can recursively lookup url params.
367
+ Returns:
368
+ url: the url string to use in requests.
369
+ method: one of get/post/patch/delete.
370
+ """
371
+
372
+ best_match_url = None
373
+ best_match_method = None
374
+ best_match_count = -1
375
+
376
+ ids = _read_app_info(request_dict)
377
+ app_id, user_id = ids if ids else (None, None)
378
+
379
+ all_fields = []
380
+ best_match_url_fields = None
381
+ for url_template, method in resources:
382
+ all_arguments_translated = True
383
+
384
+ url = url_template
385
+ count = 0
386
+ url_fields = list(re.findall(URL_TEMPLATE_PARAM_REGEX, url_template))
387
+ for field in url_fields:
388
+ field_name = field.split(".")[-1]
389
+
390
+ if field_name == "app_id":
391
+ field_value = app_id
392
+ elif field_name == "user_id":
393
+ if user_id:
394
+ field_value = user_id
395
+ else:
396
+ # "me" is the alias for the ID of the authorized user.
397
+ field_value = "me"
398
+ else:
399
+ field_value = request_dict.get(field_name)
400
+ if not field_value:
401
+ all_arguments_translated = False
402
+ break
403
+
404
+ count += 1
405
+
406
+ url = url.replace("{" + field + "}", field_value)
407
+
408
+ all_fields.extend(url_fields)
409
+
410
+ if all_arguments_translated:
411
+ if best_match_count < count:
412
+ best_match_url = url
413
+ best_match_url_fields = url_fields
414
+ best_match_method = method
415
+ best_match_count = count
416
+
417
+ if not best_match_url:
418
+ raise Exception(
419
+ "You must set one case of the following fields in your request proto: %s" % all_fields
420
+ )
421
+
422
+ return best_match_url, best_match_method, best_match_url_fields