pulp_2to3_migration_client 0.2.0b4.dev01592833441 → 0.2.0b4.dev01592853251

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/lib/pulp_2to3_migration_client/version.rb +1 -1
  4. metadata +1 -40
  5. data/pulpcore/__init__.py +0 -2
  6. data/pulpcore/client/__init__.py +0 -2
  7. data/pulpcore/client/pulp_2to3_migration/__init__.py +0 -42
  8. data/pulpcore/client/pulp_2to3_migration/api/__init__.py +0 -8
  9. data/pulpcore/client/pulp_2to3_migration/api/migration_plans_api.py +0 -609
  10. data/pulpcore/client/pulp_2to3_migration/api/pulp2content_api.py +0 -317
  11. data/pulpcore/client/pulp_2to3_migration/api/pulp2repositories_api.py +0 -289
  12. data/pulpcore/client/pulp_2to3_migration/api_client.py +0 -647
  13. data/pulpcore/client/pulp_2to3_migration/configuration.py +0 -387
  14. data/pulpcore/client/pulp_2to3_migration/exceptions.py +0 -120
  15. data/pulpcore/client/pulp_2to3_migration/models/__init__.py +0 -25
  16. data/pulpcore/client/pulp_2to3_migration/models/async_operation_response.py +0 -123
  17. data/pulpcore/client/pulp_2to3_migration/models/inline_response200.py +0 -198
  18. data/pulpcore/client/pulp_2to3_migration/models/inline_response2001.py +0 -198
  19. data/pulpcore/client/pulp_2to3_migration/models/inline_response2002.py +0 -198
  20. data/pulpcore/client/pulp_2to3_migration/models/migration_plan_run.py +0 -150
  21. data/pulpcore/client/pulp_2to3_migration/models/pulp2to3_migration_migration_plan.py +0 -177
  22. data/pulpcore/client/pulp_2to3_migration/models/pulp2to3_migration_migration_plan_read.py +0 -177
  23. data/pulpcore/client/pulp_2to3_migration/models/pulp2to3_migration_pulp2_content_read.py +0 -353
  24. data/pulpcore/client/pulp_2to3_migration/models/pulp2to3_migration_pulp2_repository_read.py +0 -441
  25. data/pulpcore/client/pulp_2to3_migration/rest.py +0 -296
  26. data/requirements.txt +0 -6
  27. data/setup.cfg +0 -2
  28. data/setup.py +0 -41
  29. data/test-requirements.txt +0 -3
  30. data/test/__init__.py +0 -0
  31. data/test/test_async_operation_response.py +0 -53
  32. data/test/test_inline_response200.py +0 -67
  33. data/test/test_inline_response2001.py +0 -79
  34. data/test/test_inline_response2002.py +0 -89
  35. data/test/test_migration_plan_run.py +0 -53
  36. data/test/test_migration_plans_api.py +0 -68
  37. data/test/test_pulp2content_api.py +0 -47
  38. data/test/test_pulp2repositories_api.py +0 -47
  39. data/test/test_pulp2to3_migration_migration_plan.py +0 -55
  40. data/test/test_pulp2to3_migration_migration_plan_read.py +0 -55
  41. data/test/test_pulp2to3_migration_pulp2_content_read.py +0 -64
  42. data/test/test_pulp2to3_migration_pulp2_repository_read.py +0 -68
  43. data/tox.ini +0 -9
@@ -1,647 +0,0 @@
1
- # coding: utf-8
2
- """
3
- Pulp 3 API
4
-
5
- No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) # noqa: E501
6
-
7
- The version of the OpenAPI document: v3
8
- Generated by: https://openapi-generator.tech
9
- """
10
-
11
- from __future__ import absolute_import
12
-
13
- import atexit
14
- import datetime
15
- from dateutil.parser import parse
16
- import json
17
- import mimetypes
18
- from multiprocessing.pool import ThreadPool
19
- import os
20
- import re
21
- import tempfile
22
-
23
- # python 2 and python 3 compatibility library
24
- import six
25
- from six.moves.urllib.parse import quote
26
-
27
- from pulpcore.client.pulp_2to3_migration.configuration import Configuration
28
- import pulpcore.client.pulp_2to3_migration.models
29
- from pulpcore.client.pulp_2to3_migration import rest
30
- from pulpcore.client.pulp_2to3_migration.exceptions import ApiValueError
31
-
32
-
33
- class ApiClient(object):
34
- """Generic API client for OpenAPI client library builds.
35
-
36
- OpenAPI generic API client. This client handles the client-
37
- server communication, and is invariant across implementations. Specifics of
38
- the methods and models for each application are generated from the OpenAPI
39
- templates.
40
-
41
- NOTE: This class is auto generated by OpenAPI Generator.
42
- Ref: https://openapi-generator.tech
43
- Do not edit the class manually.
44
-
45
- :param configuration: .Configuration object for this client
46
- :param header_name: a header to pass when making calls to the API.
47
- :param header_value: a header value to pass when making calls to
48
- the API.
49
- :param cookie: a cookie to include in the header when making calls
50
- to the API
51
- :param pool_threads: The number of threads to use for async requests
52
- to the API. More threads means more concurrent API requests.
53
- """
54
-
55
- PRIMITIVE_TYPES = (float, bool, bytes, six.text_type) + six.integer_types
56
- NATIVE_TYPES_MAPPING = {
57
- 'int': int,
58
- 'long': int if six.PY3 else long, # noqa: F821
59
- 'float': float,
60
- 'str': str,
61
- 'bool': bool,
62
- 'date': datetime.date,
63
- 'datetime': datetime.datetime,
64
- 'object': object,
65
- }
66
- _pool = None
67
-
68
- def __init__(self, configuration=None, header_name=None, header_value=None,
69
- cookie=None, pool_threads=1):
70
- if configuration is None:
71
- configuration = Configuration()
72
- self.configuration = configuration
73
- self.pool_threads = pool_threads
74
-
75
- self.rest_client = rest.RESTClientObject(configuration)
76
- self.default_headers = {}
77
- if header_name is not None:
78
- self.default_headers[header_name] = header_value
79
- self.cookie = cookie
80
- # Set default User-Agent.
81
- self.user_agent = 'OpenAPI-Generator/0.2.0b4.dev0/python'
82
- self.client_side_validation = configuration.client_side_validation
83
-
84
- def __enter__(self):
85
- return self
86
-
87
- def __exit__(self, exc_type, exc_value, traceback):
88
- self.close()
89
-
90
- def close(self):
91
- if self._pool:
92
- self._pool.close()
93
- self._pool.join()
94
- self._pool = None
95
- if hasattr(atexit, 'unregister'):
96
- atexit.unregister(self.close)
97
-
98
- @property
99
- def pool(self):
100
- """Create thread pool on first request
101
- avoids instantiating unused threadpool for blocking clients.
102
- """
103
- if self._pool is None:
104
- atexit.register(self.close)
105
- self._pool = ThreadPool(self.pool_threads)
106
- return self._pool
107
-
108
- @property
109
- def user_agent(self):
110
- """User agent for this API client"""
111
- return self.default_headers['User-Agent']
112
-
113
- @user_agent.setter
114
- def user_agent(self, value):
115
- self.default_headers['User-Agent'] = value
116
-
117
- def set_default_header(self, header_name, header_value):
118
- self.default_headers[header_name] = header_value
119
-
120
- def __call_api(
121
- self, resource_path, method, path_params=None,
122
- query_params=None, header_params=None, body=None, post_params=None,
123
- files=None, response_type=None, auth_settings=None,
124
- _return_http_data_only=None, collection_formats=None,
125
- _preload_content=True, _request_timeout=None, _host=None):
126
-
127
- config = self.configuration
128
-
129
- # header parameters
130
- header_params = header_params or {}
131
- header_params.update(self.default_headers)
132
- if self.cookie:
133
- header_params['Cookie'] = self.cookie
134
- if header_params:
135
- header_params = self.sanitize_for_serialization(header_params)
136
- header_params = dict(self.parameters_to_tuples(header_params,
137
- collection_formats))
138
-
139
- # path parameters
140
- if path_params:
141
- path_params = self.sanitize_for_serialization(path_params)
142
- path_params = self.parameters_to_tuples(path_params,
143
- collection_formats)
144
- for k, v in path_params:
145
- # specified safe chars, encode everything
146
- resource_path = resource_path.replace(
147
- '{%s}' % k,
148
- quote(str(v), safe=config.safe_chars_for_path_param)
149
- )
150
-
151
- # query parameters
152
- if query_params:
153
- query_params = self.sanitize_for_serialization(query_params)
154
- query_params = self.parameters_to_tuples(query_params,
155
- collection_formats)
156
-
157
- # post parameters
158
- if post_params or files:
159
- post_params = post_params if post_params else []
160
- post_params = self.sanitize_for_serialization(post_params)
161
- post_params = self.parameters_to_tuples(post_params,
162
- collection_formats)
163
- post_params.extend(self.files_parameters(files))
164
-
165
- # auth setting
166
- self.update_params_for_auth(header_params, query_params, auth_settings)
167
-
168
- # body
169
- if body:
170
- body = self.sanitize_for_serialization(body)
171
-
172
- # request url
173
- if _host is None:
174
- url = self.configuration.host + resource_path
175
- else:
176
- # use server/host defined in path or operation instead
177
- url = _host + resource_path
178
-
179
- # perform request and return response
180
- response_data = self.request(
181
- method, url, query_params=query_params, headers=header_params,
182
- post_params=post_params, body=body,
183
- _preload_content=_preload_content,
184
- _request_timeout=_request_timeout)
185
-
186
- self.last_response = response_data
187
-
188
- return_data = response_data
189
- if _preload_content:
190
- # deserialize response data
191
- if response_type:
192
- return_data = self.deserialize(response_data, response_type)
193
- else:
194
- return_data = None
195
-
196
- if _return_http_data_only:
197
- return (return_data)
198
- else:
199
- return (return_data, response_data.status,
200
- response_data.getheaders())
201
-
202
- def sanitize_for_serialization(self, obj):
203
- """Builds a JSON POST object.
204
-
205
- If obj is None, return None.
206
- If obj is str, int, long, float, bool, return directly.
207
- If obj is datetime.datetime, datetime.date
208
- convert to string in iso8601 format.
209
- If obj is list, sanitize each element in the list.
210
- If obj is dict, return the dict.
211
- If obj is OpenAPI model, return the properties dict.
212
-
213
- :param obj: The data to serialize.
214
- :return: The serialized form of data.
215
- """
216
- if obj is None:
217
- return None
218
- elif isinstance(obj, self.PRIMITIVE_TYPES):
219
- return obj
220
- elif isinstance(obj, list):
221
- return [self.sanitize_for_serialization(sub_obj)
222
- for sub_obj in obj]
223
- elif isinstance(obj, tuple):
224
- return tuple(self.sanitize_for_serialization(sub_obj)
225
- for sub_obj in obj)
226
- elif isinstance(obj, (datetime.datetime, datetime.date)):
227
- return obj.isoformat()
228
-
229
- if isinstance(obj, dict):
230
- obj_dict = obj
231
- else:
232
- # Convert model obj to dict except
233
- # attributes `openapi_types`, `attribute_map`
234
- # and attributes which value is not None.
235
- # Convert attribute name to json key in
236
- # model definition for request.
237
- obj_dict = {obj.attribute_map[attr]: getattr(obj, attr)
238
- for attr, _ in six.iteritems(obj.openapi_types)
239
- if getattr(obj, attr) is not None}
240
-
241
- return {key: self.sanitize_for_serialization(val)
242
- for key, val in six.iteritems(obj_dict)}
243
-
244
- def deserialize(self, response, response_type):
245
- """Deserializes response into an object.
246
-
247
- :param response: RESTResponse object to be deserialized.
248
- :param response_type: class literal for
249
- deserialized object, or string of class name.
250
-
251
- :return: deserialized object.
252
- """
253
- # handle file downloading
254
- # save response body into a tmp file and return the instance
255
- if response_type == "file":
256
- return self.__deserialize_file(response)
257
-
258
- # fetch data from response object
259
- try:
260
- data = json.loads(response.data)
261
- except ValueError:
262
- data = response.data
263
-
264
- return self.__deserialize(data, response_type)
265
-
266
- def __deserialize(self, data, klass):
267
- """Deserializes dict, list, str into an object.
268
-
269
- :param data: dict, list or str.
270
- :param klass: class literal, or string of class name.
271
-
272
- :return: object.
273
- """
274
- if data is None:
275
- return None
276
-
277
- if type(klass) == str:
278
- if klass.startswith('list['):
279
- sub_kls = re.match(r'list\[(.*)\]', klass).group(1)
280
- return [self.__deserialize(sub_data, sub_kls)
281
- for sub_data in data]
282
-
283
- if klass.startswith('dict('):
284
- sub_kls = re.match(r'dict\(([^,]*), (.*)\)', klass).group(2)
285
- return {k: self.__deserialize(v, sub_kls)
286
- for k, v in six.iteritems(data)}
287
-
288
- # convert str to class
289
- if klass in self.NATIVE_TYPES_MAPPING:
290
- klass = self.NATIVE_TYPES_MAPPING[klass]
291
- else:
292
- klass = getattr(pulpcore.client.pulp_2to3_migration.models, klass)
293
-
294
- if klass in self.PRIMITIVE_TYPES:
295
- return self.__deserialize_primitive(data, klass)
296
- elif klass == object:
297
- return self.__deserialize_object(data)
298
- elif klass == datetime.date:
299
- return self.__deserialize_date(data)
300
- elif klass == datetime.datetime:
301
- return self.__deserialize_datetime(data)
302
- else:
303
- return self.__deserialize_model(data, klass)
304
-
305
- def call_api(self, resource_path, method,
306
- path_params=None, query_params=None, header_params=None,
307
- body=None, post_params=None, files=None,
308
- response_type=None, auth_settings=None, async_req=None,
309
- _return_http_data_only=None, collection_formats=None,
310
- _preload_content=True, _request_timeout=None, _host=None):
311
- """Makes the HTTP request (synchronous) and returns deserialized data.
312
-
313
- To make an async_req request, set the async_req parameter.
314
-
315
- :param resource_path: Path to method endpoint.
316
- :param method: Method to call.
317
- :param path_params: Path parameters in the url.
318
- :param query_params: Query parameters in the url.
319
- :param header_params: Header parameters to be
320
- placed in the request header.
321
- :param body: Request body.
322
- :param post_params dict: Request post form parameters,
323
- for `application/x-www-form-urlencoded`, `multipart/form-data`.
324
- :param auth_settings list: Auth Settings names for the request.
325
- :param response: Response data type.
326
- :param files dict: key -> filename, value -> filepath,
327
- for `multipart/form-data`.
328
- :param async_req bool: execute request asynchronously
329
- :param _return_http_data_only: response data without head status code
330
- and headers
331
- :param collection_formats: dict of collection formats for path, query,
332
- header, and post parameters.
333
- :param _preload_content: if False, the urllib3.HTTPResponse object will
334
- be returned without reading/decoding response
335
- data. Default is True.
336
- :param _request_timeout: timeout setting for this request. If one
337
- number provided, it will be total request
338
- timeout. It can also be a pair (tuple) of
339
- (connection, read) timeouts.
340
- :return:
341
- If async_req parameter is True,
342
- the request will be called asynchronously.
343
- The method will return the request thread.
344
- If parameter async_req is False or missing,
345
- then the method will return the response directly.
346
- """
347
- if not async_req:
348
- return self.__call_api(resource_path, method,
349
- path_params, query_params, header_params,
350
- body, post_params, files,
351
- response_type, auth_settings,
352
- _return_http_data_only, collection_formats,
353
- _preload_content, _request_timeout, _host)
354
-
355
- return self.pool.apply_async(self.__call_api, (resource_path,
356
- method, path_params,
357
- query_params,
358
- header_params, body,
359
- post_params, files,
360
- response_type,
361
- auth_settings,
362
- _return_http_data_only,
363
- collection_formats,
364
- _preload_content,
365
- _request_timeout,
366
- _host))
367
-
368
- def request(self, method, url, query_params=None, headers=None,
369
- post_params=None, body=None, _preload_content=True,
370
- _request_timeout=None):
371
- """Makes the HTTP request using RESTClient."""
372
- if method == "GET":
373
- return self.rest_client.GET(url,
374
- query_params=query_params,
375
- _preload_content=_preload_content,
376
- _request_timeout=_request_timeout,
377
- headers=headers)
378
- elif method == "HEAD":
379
- return self.rest_client.HEAD(url,
380
- query_params=query_params,
381
- _preload_content=_preload_content,
382
- _request_timeout=_request_timeout,
383
- headers=headers)
384
- elif method == "OPTIONS":
385
- return self.rest_client.OPTIONS(url,
386
- query_params=query_params,
387
- headers=headers,
388
- _preload_content=_preload_content,
389
- _request_timeout=_request_timeout)
390
- elif method == "POST":
391
- return self.rest_client.POST(url,
392
- query_params=query_params,
393
- headers=headers,
394
- post_params=post_params,
395
- _preload_content=_preload_content,
396
- _request_timeout=_request_timeout,
397
- body=body)
398
- elif method == "PUT":
399
- return self.rest_client.PUT(url,
400
- query_params=query_params,
401
- headers=headers,
402
- post_params=post_params,
403
- _preload_content=_preload_content,
404
- _request_timeout=_request_timeout,
405
- body=body)
406
- elif method == "PATCH":
407
- return self.rest_client.PATCH(url,
408
- query_params=query_params,
409
- headers=headers,
410
- post_params=post_params,
411
- _preload_content=_preload_content,
412
- _request_timeout=_request_timeout,
413
- body=body)
414
- elif method == "DELETE":
415
- return self.rest_client.DELETE(url,
416
- query_params=query_params,
417
- headers=headers,
418
- _preload_content=_preload_content,
419
- _request_timeout=_request_timeout,
420
- body=body)
421
- else:
422
- raise ApiValueError(
423
- "http method must be `GET`, `HEAD`, `OPTIONS`,"
424
- " `POST`, `PATCH`, `PUT` or `DELETE`."
425
- )
426
-
427
- def parameters_to_tuples(self, params, collection_formats):
428
- """Get parameters as list of tuples, formatting collections.
429
-
430
- :param params: Parameters as dict or list of two-tuples
431
- :param dict collection_formats: Parameter collection formats
432
- :return: Parameters as list of tuples, collections formatted
433
- """
434
- new_params = []
435
- if collection_formats is None:
436
- collection_formats = {}
437
- for k, v in six.iteritems(params) if isinstance(params, dict) else params: # noqa: E501
438
- if k in collection_formats:
439
- collection_format = collection_formats[k]
440
- if collection_format == 'multi':
441
- new_params.extend((k, value) for value in v)
442
- else:
443
- if collection_format == 'ssv':
444
- delimiter = ' '
445
- elif collection_format == 'tsv':
446
- delimiter = '\t'
447
- elif collection_format == 'pipes':
448
- delimiter = '|'
449
- else: # csv is the default
450
- delimiter = ','
451
- new_params.append(
452
- (k, delimiter.join(str(value) for value in v)))
453
- else:
454
- new_params.append((k, v))
455
- return new_params
456
-
457
- def files_parameters(self, files=None):
458
- """Builds form parameters.
459
-
460
- :param files: File parameters.
461
- :return: Form parameters with files.
462
- """
463
- params = []
464
-
465
- if files:
466
- for k, v in six.iteritems(files):
467
- if not v:
468
- continue
469
- file_names = v if type(v) is list else [v]
470
- for n in file_names:
471
- with open(n, 'rb') as f:
472
- filename = os.path.basename(f.name)
473
- filedata = f.read()
474
- mimetype = (mimetypes.guess_type(filename)[0] or
475
- 'application/octet-stream')
476
- params.append(
477
- tuple([k, tuple([filename, filedata, mimetype])]))
478
-
479
- return params
480
-
481
- def select_header_accept(self, accepts):
482
- """Returns `Accept` based on an array of accepts provided.
483
-
484
- :param accepts: List of headers.
485
- :return: Accept (e.g. application/json).
486
- """
487
- if not accepts:
488
- return
489
-
490
- accepts = [x.lower() for x in accepts]
491
-
492
- if 'application/json' in accepts:
493
- return 'application/json'
494
- else:
495
- return ', '.join(accepts)
496
-
497
- def select_header_content_type(self, content_types):
498
- """Returns `Content-Type` based on an array of content_types provided.
499
-
500
- :param content_types: List of content-types.
501
- :return: Content-Type (e.g. application/json).
502
- """
503
- if not content_types:
504
- return 'application/json'
505
-
506
- content_types = [x.lower() for x in content_types]
507
-
508
- if 'application/json' in content_types or '*/*' in content_types:
509
- return 'application/json'
510
- else:
511
- return content_types[0]
512
-
513
- def update_params_for_auth(self, headers, querys, auth_settings):
514
- """Updates header and query params based on authentication setting.
515
-
516
- :param headers: Header parameters dict to be updated.
517
- :param querys: Query parameters tuple list to be updated.
518
- :param auth_settings: Authentication setting identifiers list.
519
- """
520
- if not auth_settings:
521
- return
522
-
523
- for auth in auth_settings:
524
- auth_setting = self.configuration.auth_settings().get(auth)
525
- if auth_setting:
526
- if auth_setting['in'] == 'cookie':
527
- headers['Cookie'] = auth_setting['value']
528
- elif auth_setting['in'] == 'header':
529
- headers[auth_setting['key']] = auth_setting['value']
530
- elif auth_setting['in'] == 'query':
531
- querys.append((auth_setting['key'], auth_setting['value']))
532
- else:
533
- raise ApiValueError(
534
- 'Authentication token must be in `query` or `header`'
535
- )
536
-
537
- def __deserialize_file(self, response):
538
- """Deserializes body to file
539
-
540
- Saves response body into a file in a temporary folder,
541
- using the filename from the `Content-Disposition` header if provided.
542
-
543
- :param response: RESTResponse.
544
- :return: file path.
545
- """
546
- fd, path = tempfile.mkstemp(dir=self.configuration.temp_folder_path)
547
- os.close(fd)
548
- os.remove(path)
549
-
550
- content_disposition = response.getheader("Content-Disposition")
551
- if content_disposition:
552
- filename = re.search(r'filename=[\'"]?([^\'"\s]+)[\'"]?',
553
- content_disposition).group(1)
554
- path = os.path.join(os.path.dirname(path), filename)
555
-
556
- with open(path, "wb") as f:
557
- f.write(response.data)
558
-
559
- return path
560
-
561
- def __deserialize_primitive(self, data, klass):
562
- """Deserializes string to primitive type.
563
-
564
- :param data: str.
565
- :param klass: class literal.
566
-
567
- :return: int, long, float, str, bool.
568
- """
569
- try:
570
- return klass(data)
571
- except UnicodeEncodeError:
572
- return six.text_type(data)
573
- except TypeError:
574
- return data
575
-
576
- def __deserialize_object(self, value):
577
- """Return an original value.
578
-
579
- :return: object.
580
- """
581
- return value
582
-
583
- def __deserialize_date(self, string):
584
- """Deserializes string to date.
585
-
586
- :param string: str.
587
- :return: date.
588
- """
589
- try:
590
- return parse(string).date()
591
- except ImportError:
592
- return string
593
- except ValueError:
594
- raise rest.ApiException(
595
- status=0,
596
- reason="Failed to parse `{0}` as date object".format(string)
597
- )
598
-
599
- def __deserialize_datetime(self, string):
600
- """Deserializes string to datetime.
601
-
602
- The string should be in iso8601 datetime format.
603
-
604
- :param string: str.
605
- :return: datetime.
606
- """
607
- try:
608
- return parse(string)
609
- except ImportError:
610
- return string
611
- except ValueError:
612
- raise rest.ApiException(
613
- status=0,
614
- reason=(
615
- "Failed to parse `{0}` as datetime object"
616
- .format(string)
617
- )
618
- )
619
-
620
- def __deserialize_model(self, data, klass):
621
- """Deserializes list or dict to model.
622
-
623
- :param data: dict, list.
624
- :param klass: class literal.
625
- :return: model object.
626
- """
627
-
628
- if not klass.openapi_types and not hasattr(klass,
629
- 'get_real_child_model'):
630
- return data
631
-
632
- kwargs = {}
633
- if (data is not None and
634
- klass.openapi_types is not None and
635
- isinstance(data, (list, dict))):
636
- for attr, attr_type in six.iteritems(klass.openapi_types):
637
- if klass.attribute_map[attr] in data:
638
- value = data[klass.attribute_map[attr]]
639
- kwargs[attr] = self.__deserialize(value, attr_type)
640
-
641
- instance = klass(**kwargs)
642
-
643
- if hasattr(instance, 'get_real_child_model'):
644
- klass_name = instance.get_real_child_model(data)
645
- if klass_name:
646
- instance = self.__deserialize(data, klass_name)
647
- return instance