Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/django/db/models/utils.py: 50%

34 statements  

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

1import functools 

2from collections import namedtuple 

3 

4 

5def make_model_tuple(model): 

6 """ 

7 Take a model or a string of the form "app_label.ModelName" and return a 

8 corresponding ("app_label", "modelname") tuple. If a tuple is passed in, 

9 assume it's a valid model tuple already and return it unchanged. 

10 """ 

11 try: 

12 if isinstance(model, tuple): 

13 model_tuple = model 

14 elif isinstance(model, str): 

15 app_label, model_name = model.split(".") 

16 model_tuple = app_label, model_name.lower() 

17 else: 

18 model_tuple = model._meta.app_label, model._meta.model_name 

19 assert len(model_tuple) == 2 

20 return model_tuple 

21 except (ValueError, AssertionError): 

22 raise ValueError( 

23 "Invalid model reference '%s'. String model references " 

24 "must be of the form 'app_label.ModelName'." % model 

25 ) 

26 

27 

28def resolve_callables(mapping): 

29 """ 

30 Generate key/value pairs for the given mapping where the values are 

31 evaluated if they're callable. 

32 """ 

33 for k, v in mapping.items(): 

34 yield k, v() if callable(v) else v 

35 

36 

37def unpickle_named_row(names, values): 

38 return create_namedtuple_class(*names)(*values) 

39 

40 

41@functools.lru_cache 

42def create_namedtuple_class(*names): 

43 # Cache type() with @lru_cache since it's too slow to be called for every 

44 # QuerySet evaluation. 

45 def __reduce__(self): 

46 return unpickle_named_row, (names, tuple(self)) 

47 

48 return type( 

49 "Row", 

50 (namedtuple("Row", names),), 

51 {"__reduce__": __reduce__, "__slots__": ()}, 

52 ) 

53 

54 

55class AltersData: 

56 """ 

57 Make subclasses preserve the alters_data attribute on overridden methods. 

58 """ 

59 

60 def __init_subclass__(cls, **kwargs): 

61 for fn_name, fn in vars(cls).items(): 

62 if callable(fn) and not hasattr(fn, "alters_data"): 

63 for base in cls.__bases__: 

64 if base_fn := getattr(base, fn_name, None): 

65 if hasattr(base_fn, "alters_data"): 

66 fn.alters_data = base_fn.alters_data 

67 break 

68 

69 super().__init_subclass__(**kwargs)