Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/jsonpickle/util.py: 38%

168 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:20 +0000

1# Copyright (C) 2008 John Paulett (john -at- paulett.org) 

2# Copyright (C) 2009-2018 David Aguilar (davvid -at- gmail.com) 

3# All rights reserved. 

4# 

5# This software is licensed as described in the file COPYING, which 

6# you should have received as part of this distribution. 

7 

8"""Helper functions for pickling and unpickling. Most functions assist in 

9determining the type of an object. 

10""" 

11from __future__ import absolute_import, division, unicode_literals 

12 

13import base64 

14import collections 

15import inspect 

16import io 

17import operator 

18import sys 

19import time 

20import types 

21 

22from . import compat, tags 

23from .compat import abc_iterator, class_types, iterator_types, numeric_types 

24 

25SEQUENCES = (list, set, tuple) 

26SEQUENCES_SET = {list, set, tuple} 

27PRIMITIVES = {compat.ustr, bool, type(None)} | set(numeric_types) 

28FUNCTION_TYPES = { 

29 types.FunctionType, 

30 types.MethodType, 

31 types.LambdaType, 

32 types.BuiltinFunctionType, 

33 types.BuiltinMethodType, 

34} 

35NON_REDUCIBLE_TYPES = ( 

36 { 

37 list, 

38 dict, 

39 set, 

40 tuple, 

41 object, 

42 bytes, 

43 } 

44 | PRIMITIVES 

45 | FUNCTION_TYPES 

46) 

47NON_CLASS_TYPES = { 

48 list, 

49 dict, 

50 set, 

51 tuple, 

52 bytes, 

53} | PRIMITIVES 

54 

55 

56def is_type(obj): 

57 """Returns True is obj is a reference to a type. 

58 

59 >>> is_type(1) 

60 False 

61 

62 >>> is_type(object) 

63 True 

64 

65 >>> class Klass: pass 

66 >>> is_type(Klass) 

67 True 

68 """ 

69 # use "isinstance" and not "is" to allow for metaclasses 

70 return isinstance(obj, class_types) 

71 

72 

73def has_method(obj, name): 

74 # false if attribute doesn't exist 

75 if not hasattr(obj, name): 

76 return False 

77 func = getattr(obj, name) 

78 

79 # builtin descriptors like __getnewargs__ 

80 if isinstance(func, types.BuiltinMethodType): 

81 return True 

82 

83 # note that FunctionType has a different meaning in py2/py3 

84 if not isinstance(func, (types.MethodType, types.FunctionType)): 

85 return False 

86 

87 # need to go through __dict__'s since in py3 

88 # methods are essentially descriptors 

89 

90 # __class__ for old-style classes 

91 base_type = obj if is_type(obj) else obj.__class__ 

92 original = None 

93 # there is no .mro() for old-style classes 

94 for subtype in inspect.getmro(base_type): 

95 original = vars(subtype).get(name) 

96 if original is not None: 

97 break 

98 

99 # name not found in the mro 

100 if original is None: 

101 return False 

102 

103 # static methods are always fine 

104 if isinstance(original, staticmethod): 

105 return True 

106 

107 # at this point, the method has to be an instancemthod or a classmethod 

108 if not hasattr(func, '__self__'): 

109 return False 

110 bound_to = getattr(func, '__self__') 

111 

112 # class methods 

113 if isinstance(original, classmethod): 

114 return issubclass(base_type, bound_to) 

115 

116 # bound methods 

117 return isinstance(obj, type(bound_to)) 

118 

119 

120def is_object(obj): 

121 """Returns True is obj is a reference to an object instance. 

122 

123 >>> is_object(1) 

124 True 

125 

126 >>> is_object(object()) 

127 True 

128 

129 >>> is_object(lambda x: 1) 

130 False 

131 """ 

132 return isinstance(obj, object) and not isinstance( 

133 obj, (type, types.FunctionType, types.BuiltinFunctionType) 

134 ) 

135 

136 

137def is_not_class(obj): 

138 """Determines if the object is not a class or a class instance. 

139 Used for serializing properties. 

140 """ 

141 return type(obj) in NON_CLASS_TYPES 

142 

143 

144def is_primitive(obj): 

145 """Helper method to see if the object is a basic data type. Unicode strings, 

146 integers, longs, floats, booleans, and None are considered primitive 

147 and will return True when passed into *is_primitive()* 

148 

149 >>> is_primitive(3) 

150 True 

151 >>> is_primitive([4,4]) 

152 False 

153 """ 

154 return type(obj) in PRIMITIVES 

155 

156 

157def is_enum(obj): 

158 """Is the object an enum?""" 

159 return 'enum' in sys.modules and isinstance(obj, sys.modules['enum'].Enum) 

160 

161 

162def is_dictionary(obj): 

163 """Helper method for testing if the object is a dictionary. 

164 

165 >>> is_dictionary({'key':'value'}) 

166 True 

167 

168 """ 

169 return type(obj) is dict 

170 

171 

172def is_sequence(obj): 

173 """Helper method to see if the object is a sequence (list, set, or tuple). 

174 

175 >>> is_sequence([4]) 

176 True 

177 

178 """ 

179 return type(obj) in SEQUENCES_SET 

180 

181 

182def is_list(obj): 

183 """Helper method to see if the object is a Python list. 

184 

185 >>> is_list([4]) 

186 True 

187 """ 

188 return type(obj) is list 

189 

190 

191def is_set(obj): 

192 """Helper method to see if the object is a Python set. 

193 

194 >>> is_set(set()) 

195 True 

196 """ 

197 return type(obj) is set 

198 

199 

200def is_bytes(obj): 

201 """Helper method to see if the object is a bytestring. 

202 

203 >>> is_bytes(b'foo') 

204 True 

205 """ 

206 return type(obj) is bytes 

207 

208 

209def is_unicode(obj): 

210 """Helper method to see if the object is a unicode string""" 

211 return type(obj) is compat.ustr 

212 

213 

214def is_tuple(obj): 

215 """Helper method to see if the object is a Python tuple. 

216 

217 >>> is_tuple((1,)) 

218 True 

219 """ 

220 return type(obj) is tuple 

221 

222 

223def is_dictionary_subclass(obj): 

224 """Returns True if *obj* is a subclass of the dict type. *obj* must be 

225 a subclass and not the actual builtin dict. 

226 

227 >>> class Temp(dict): pass 

228 >>> is_dictionary_subclass(Temp()) 

229 True 

230 """ 

231 # TODO: add UserDict 

232 return ( 

233 hasattr(obj, '__class__') 

234 and issubclass(obj.__class__, dict) 

235 and type(obj) is not dict 

236 ) 

237 

238 

239def is_sequence_subclass(obj): 

240 """Returns True if *obj* is a subclass of list, set or tuple. 

241 

242 *obj* must be a subclass and not the actual builtin, such 

243 as list, set, tuple, etc.. 

244 

245 >>> class Temp(list): pass 

246 >>> is_sequence_subclass(Temp()) 

247 True 

248 """ 

249 return ( 

250 hasattr(obj, '__class__') 

251 and issubclass(obj.__class__, SEQUENCES) 

252 and not is_sequence(obj) 

253 ) 

254 

255 

256def is_noncomplex(obj): 

257 """Returns True if *obj* is a special (weird) class, that is more complex 

258 than primitive data types, but is not a full object. Including: 

259 

260 * :class:`~time.struct_time` 

261 """ 

262 if type(obj) is time.struct_time: 

263 return True 

264 return False 

265 

266 

267def is_function(obj): 

268 """Returns true if passed a function 

269 

270 >>> is_function(lambda x: 1) 

271 True 

272 

273 >>> is_function(locals) 

274 True 

275 

276 >>> def method(): pass 

277 >>> is_function(method) 

278 True 

279 

280 >>> is_function(1) 

281 False 

282 """ 

283 return type(obj) in FUNCTION_TYPES 

284 

285 

286def is_module_function(obj): 

287 """Return True if `obj` is a module-global function 

288 

289 >>> import os 

290 >>> is_module_function(os.path.exists) 

291 True 

292 

293 >>> is_module_function(lambda: None) 

294 False 

295 

296 """ 

297 

298 return ( 

299 hasattr(obj, '__class__') 

300 and isinstance(obj, (types.FunctionType, types.BuiltinFunctionType)) 

301 and hasattr(obj, '__module__') 

302 and hasattr(obj, '__name__') 

303 and obj.__name__ != '<lambda>' 

304 ) 

305 

306 

307def is_module(obj): 

308 """Returns True if passed a module 

309 

310 >>> import os 

311 >>> is_module(os) 

312 True 

313 

314 """ 

315 return isinstance(obj, types.ModuleType) 

316 

317 

318def is_picklable(name, value): 

319 """Return True if an object can be pickled 

320 

321 >>> import os 

322 >>> is_picklable('os', os) 

323 True 

324 

325 >>> def foo(): pass 

326 >>> is_picklable('foo', foo) 

327 True 

328 

329 >>> is_picklable('foo', lambda: None) 

330 False 

331 

332 """ 

333 if name in tags.RESERVED: 

334 return False 

335 return is_module_function(value) or not is_function(value) 

336 

337 

338def is_installed(module): 

339 """Tests to see if ``module`` is available on the sys.path 

340 

341 >>> is_installed('sys') 

342 True 

343 >>> is_installed('hopefullythisisnotarealmodule') 

344 False 

345 

346 """ 

347 try: 

348 __import__(module) 

349 return True 

350 except ImportError: 

351 return False 

352 

353 

354def is_list_like(obj): 

355 return hasattr(obj, '__getitem__') and hasattr(obj, 'append') 

356 

357 

358def is_iterator(obj): 

359 return isinstance(obj, abc_iterator) and not isinstance(obj, io.IOBase) 

360 

361 

362def is_collections(obj): 

363 try: 

364 return type(obj).__module__ == 'collections' 

365 except Exception: 

366 return False 

367 

368 

369def is_reducible_sequence_subclass(obj): 

370 return hasattr(obj, '__class__') and issubclass(obj.__class__, SEQUENCES) 

371 

372 

373def is_reducible(obj): 

374 """ 

375 Returns false if of a type which have special casing, 

376 and should not have their __reduce__ methods used 

377 """ 

378 # defaultdicts may contain functions which we cannot serialise 

379 if is_collections(obj) and not isinstance(obj, collections.defaultdict): 

380 return True 

381 # We turn off the formatting in order to double the speed of the function. 

382 # Condensing it into one line seems to save the parser a lot of time. 

383 # fmt: off 

384 # pylint: disable=line-too-long 

385 if type(obj) in NON_REDUCIBLE_TYPES or obj is object or is_dictionary_subclass(obj) or isinstance(obj, types.ModuleType) or is_reducible_sequence_subclass(obj) or is_list_like(obj) or isinstance(getattr(obj, '__slots__', None), iterator_types) or (is_type(obj) and obj.__module__ == 'datetime'): # noqa: E501 

386 return False 

387 # fmt: on 

388 return True 

389 

390 

391def in_dict(obj, key, default=False): 

392 """ 

393 Returns true if key exists in obj.__dict__; false if not in. 

394 If obj.__dict__ is absent, return default 

395 """ 

396 return (key in obj.__dict__) if getattr(obj, '__dict__', None) else default 

397 

398 

399def in_slots(obj, key, default=False): 

400 """ 

401 Returns true if key exists in obj.__slots__; false if not in. 

402 If obj.__slots__ is absent, return default 

403 """ 

404 return (key in obj.__slots__) if getattr(obj, '__slots__', None) else default 

405 

406 

407def has_reduce(obj): 

408 """ 

409 Tests if __reduce__ or __reduce_ex__ exists in the object dict or 

410 in the class dicts of every class in the MRO *except object*. 

411 

412 Returns a tuple of booleans (has_reduce, has_reduce_ex) 

413 """ 

414 

415 if not is_reducible(obj) or is_type(obj): 

416 return (False, False) 

417 

418 # in this case, reduce works and is desired 

419 # notwithstanding depending on default object 

420 # reduce 

421 if is_noncomplex(obj): 

422 return (False, True) 

423 

424 has_reduce = False 

425 has_reduce_ex = False 

426 

427 REDUCE = '__reduce__' 

428 REDUCE_EX = '__reduce_ex__' 

429 

430 # For object instance 

431 has_reduce = in_dict(obj, REDUCE) or in_slots(obj, REDUCE) 

432 has_reduce_ex = in_dict(obj, REDUCE_EX) or in_slots(obj, REDUCE_EX) 

433 

434 # turn to the MRO 

435 for base in type(obj).__mro__: 

436 if is_reducible(base): 

437 has_reduce = has_reduce or in_dict(base, REDUCE) 

438 has_reduce_ex = has_reduce_ex or in_dict(base, REDUCE_EX) 

439 if has_reduce and has_reduce_ex: 

440 return (has_reduce, has_reduce_ex) 

441 

442 # for things that don't have a proper dict but can be 

443 # getattred (rare, but includes some builtins) 

444 cls = type(obj) 

445 object_reduce = getattr(object, REDUCE) 

446 object_reduce_ex = getattr(object, REDUCE_EX) 

447 if not has_reduce: 

448 has_reduce_cls = getattr(cls, REDUCE, False) 

449 if has_reduce_cls is not object_reduce: 

450 has_reduce = has_reduce_cls 

451 

452 if not has_reduce_ex: 

453 has_reduce_ex_cls = getattr(cls, REDUCE_EX, False) 

454 if has_reduce_ex_cls is not object_reduce_ex: 

455 has_reduce_ex = has_reduce_ex_cls 

456 

457 return (has_reduce, has_reduce_ex) 

458 

459 

460def translate_module_name(module): 

461 """Rename builtin modules to a consistent module name. 

462 

463 Prefer the more modern naming. 

464 

465 This is used so that references to Python's `builtins` module can 

466 be loaded in both Python 2 and 3. We remap to the "__builtin__" 

467 name and unmap it when importing. 

468 

469 Map the Python2 `exceptions` module to `builtins` because 

470 `builtins` is a superset and contains everything that is 

471 available in `exceptions`, which makes the translation simpler. 

472 

473 See untranslate_module_name() for the reverse operation. 

474 """ 

475 lookup = dict(__builtin__='builtins', exceptions='builtins') 

476 return lookup.get(module, module) 

477 

478 

479def _0_9_6_compat_untranslate(module): 

480 """Provide compatibility for pickles created with jsonpickle 0.9.6 and 

481 earlier, remapping `exceptions` and `__builtin__` to `builtins`. 

482 """ 

483 lookup = dict(__builtin__='builtins', exceptions='builtins') 

484 return lookup.get(module, module) 

485 

486 

487def untranslate_module_name(module): 

488 """Rename module names mention in JSON to names that we can import 

489 

490 This reverses the translation applied by translate_module_name() to 

491 a module name available to the current version of Python. 

492 

493 """ 

494 return _0_9_6_compat_untranslate(module) 

495 

496 

497def importable_name(cls): 

498 """ 

499 >>> class Example(object): 

500 ... pass 

501 

502 >>> ex = Example() 

503 >>> importable_name(ex.__class__) == 'jsonpickle.util.Example' 

504 True 

505 >>> importable_name(type(25)) == 'builtins.int' 

506 True 

507 >>> importable_name(None.__class__) == 'builtins.NoneType' 

508 True 

509 >>> importable_name(False.__class__) == 'builtins.bool' 

510 True 

511 >>> importable_name(AttributeError) == 'builtins.AttributeError' 

512 True 

513 

514 """ 

515 # Use the fully-qualified name if available (Python >= 3.3) 

516 name = getattr(cls, '__qualname__', cls.__name__) 

517 module = translate_module_name(cls.__module__) 

518 if not module: 

519 if hasattr(cls, '__self__'): 

520 module = cls.__self__.__class__.__module__ 

521 return '{}.{}'.format(module, name) 

522 

523 

524def b64encode(data): 

525 """ 

526 Encode binary data to ascii text in base64. Data must be bytes. 

527 """ 

528 return base64.b64encode(data).decode('ascii') 

529 

530 

531def b64decode(payload): 

532 """ 

533 Decode payload - must be ascii text. 

534 """ 

535 return base64.b64decode(payload) 

536 

537 

538def b85encode(data): 

539 """ 

540 Encode binary data to ascii text in base85. Data must be bytes. 

541 """ 

542 return base64.b85encode(data).decode('ascii') 

543 

544 

545def b85decode(payload): 

546 """ 

547 Decode payload - must be ascii text. 

548 """ 

549 return base64.b85decode(payload) 

550 

551 

552def itemgetter(obj, getter=operator.itemgetter(0)): 

553 return compat.ustr(getter(obj)) 

554 

555 

556def items(obj): 

557 """ 

558 TODO: Replace all calls to this with plain dict.items() 

559 """ 

560 for k, v in obj.items(): 

561 yield k, v