Coverage for farmbot_sidecar_starter_pack/state.py: 100%

70 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-09-11 15:43 -0700

1"""State management.""" 

2 

3import json 

4import inspect 

5from datetime import datetime 

6 

7 

8def get_call_stack_depth(): 

9 """Return the depth of the current call stack.""" 

10 depth = 0 

11 frame = inspect.currentframe() 

12 while frame: 

13 depth += 1 

14 frame = frame.f_back 

15 return depth 

16 

17 

18def get_function_call_info(): 

19 """Return the name and given arguments of the function where this is called.""" 

20 # back to print_status then back to the function that called print_status 

21 frame = inspect.currentframe().f_back.f_back 

22 func_name = frame.f_code.co_name 

23 args, _, _, values = inspect.getargvalues(frame) 

24 arg_strings = [] 

25 for arg in args: 

26 if arg != "self": 

27 arg_strings.append(f"{arg}={repr(values[arg])}") 

28 arg_str = ", ".join(arg_strings) 

29 return f"{func_name}({arg_str})" 

30 

31 

32NO_TOKEN_ERROR = """ 

33ERROR: You have no token, please call `get_token` 

34using your login credentials and the server you wish to connect to. 

35""" 

36 

37 

38class State(): 

39 """State class.""" 

40 

41 NO_TOKEN_ERROR = NO_TOKEN_ERROR.replace("\n", "") 

42 

43 def __init__(self): 

44 self.token = None 

45 self.error = None 

46 self.last_messages = {} 

47 self.last_published = {} 

48 self.verbosity = 2 

49 self.json_printing = True 

50 self.timeout = { 

51 "api": 15, 

52 "listen": 15, 

53 "movements": 120, 

54 } 

55 self.test_env = False 

56 self.ssl = True 

57 self.min_call_stack_depth = 100 

58 self.dry_run = False 

59 self.resource_cache = {} 

60 

61 def print_status(self, endpoint_json=None, description=None, update_only=False, end="\n"): 

62 """Handle changes to output based on user-defined verbosity.""" 

63 depth = get_call_stack_depth() 

64 if depth < self.min_call_stack_depth: 

65 self.min_call_stack_depth = depth 

66 top = depth == self.min_call_stack_depth 

67 no_end = end == "" and description != "" 

68 indent = "" if (top or no_end) else " " * 4 

69 

70 if self.verbosity >= 2 and not update_only: 

71 if top: 

72 print() 

73 function = get_function_call_info() 

74 print(f"{indent}`{function}` called at {datetime.now()}") 

75 if self.verbosity >= 1: 

76 if self.verbosity == 1 and not update_only and top: 

77 print() 

78 if description is not None: 

79 print(indent + description, end=end, flush=end == "") 

80 if endpoint_json is not None and self.json_printing: 

81 json_str = json.dumps(endpoint_json, indent=4) 

82 indented_str = indent + json_str.replace("\n", "\n" + indent) 

83 print(indented_str) 

84 

85 def check_token(self): 

86 """Ensure the token persists throughout sidecar.""" 

87 

88 if self.token is None: 

89 self.print_status(description=self.NO_TOKEN_ERROR) 

90 self.error = self.NO_TOKEN_ERROR 

91 raise ValueError(self.NO_TOKEN_ERROR) 

92 

93 def save_cache(self, endpoint, records): 

94 """Cache records.""" 

95 self.resource_cache[endpoint] = records 

96 

97 def fetch_cache(self, endpoint): 

98 """Fetch cached records.""" 

99 return self.resource_cache.get(endpoint) 

100 

101 def clear_cache(self, endpoint=None): 

102 """Clear the cache.""" 

103 if endpoint is not None and endpoint in self.resource_cache: 

104 del self.resource_cache[endpoint] 

105 else: 

106 self.resource_cache = {}