Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/django/utils/deconstruct.py: 65%

23 statements  

« prev     ^ index     » next       coverage.py v7.0.5, created at 2023-01-17 06:13 +0000

1from importlib import import_module 

2 

3from django.utils.version import get_docs_version 

4 

5 

6def deconstructible(*args, path=None): 

7 """ 

8 Class decorator that allows the decorated class to be serialized 

9 by the migrations subsystem. 

10 

11 The `path` kwarg specifies the import path. 

12 """ 

13 

14 def decorator(klass): 

15 def __new__(cls, *args, **kwargs): 

16 # We capture the arguments to make returning them trivial 

17 obj = super(klass, cls).__new__(cls) 

18 obj._constructor_args = (args, kwargs) 

19 return obj 

20 

21 def deconstruct(obj): 

22 """ 

23 Return a 3-tuple of class import path, positional arguments, 

24 and keyword arguments. 

25 """ 

26 # Fallback version 

27 if path and type(obj) is klass: 

28 module_name, _, name = path.rpartition(".") 

29 else: 

30 module_name = obj.__module__ 

31 name = obj.__class__.__name__ 

32 # Make sure it's actually there and not an inner class 

33 module = import_module(module_name) 

34 if not hasattr(module, name): 

35 raise ValueError( 

36 "Could not find object %s in %s.\n" 

37 "Please note that you cannot serialize things like inner " 

38 "classes. Please move the object into the main module " 

39 "body to use migrations.\n" 

40 "For more information, see " 

41 "https://docs.djangoproject.com/en/%s/topics/migrations/" 

42 "#serializing-values" % (name, module_name, get_docs_version()) 

43 ) 

44 return ( 

45 path 

46 if path and type(obj) is klass 

47 else f"{obj.__class__.__module__}.{name}", 

48 obj._constructor_args[0], 

49 obj._constructor_args[1], 

50 ) 

51 

52 klass.__new__ = staticmethod(__new__) 

53 klass.deconstruct = deconstruct 

54 

55 return klass 

56 

57 if not args: 

58 return decorator 

59 return decorator(*args)