Coverage for mindsdb / api / http / namespaces / skills.py: 96%

88 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-21 00:36 +0000

1from http import HTTPStatus 

2 

3from flask import request 

4from flask_restx import Resource 

5 

6from mindsdb.metrics.metrics import api_endpoint_metrics 

7from mindsdb.api.http.namespaces.configs.projects import ns_conf 

8from mindsdb.api.http.utils import http_error 

9from mindsdb.interfaces.skills.skills_controller import SkillsController 

10from mindsdb.utilities.exception import EntityNotExistsError 

11 

12 

13def create_skill(project_name, skill): 

14 skills_controller = SkillsController() 

15 for required_field in ['name', 'type', 'params']: 

16 if required_field not in skill: 

17 return http_error( 

18 HTTPStatus.BAD_REQUEST, 

19 'Missing field', 

20 'Missing "{}" field for skill'.format(required_field) 

21 ) 

22 name = skill['name'] 

23 type = skill['type'] 

24 params = skill['params'] 

25 

26 try: 

27 existing_skill = skills_controller.get_skill(name, project_name) 

28 except ValueError: 

29 # Project needs to exist 

30 return http_error( 

31 HTTPStatus.NOT_FOUND, 

32 'Project not found', 

33 f'Project with name {project_name} does not exist' 

34 ) 

35 

36 if existing_skill is not None: 36 ↛ 37line 36 didn't jump to line 37 because the condition on line 36 was never true

37 return http_error( 

38 HTTPStatus.CONFLICT, 

39 'Skill already exists', 

40 f'Skill with name {name} already exists. Please use a different name' 

41 ) 

42 

43 new_skill = skills_controller.add_skill(name, project_name, type, params) 

44 return new_skill.as_dict(), HTTPStatus.CREATED 

45 

46 

47@ns_conf.route('/<project_name>/skills') 

48class SkillsResource(Resource): 

49 @ns_conf.doc('list_skills') 

50 @api_endpoint_metrics('GET', '/skills') 

51 def get(self, project_name): 

52 ''' List all skills''' 

53 skills_controller = SkillsController() 

54 try: 

55 all_skills = skills_controller.get_skills(project_name) 

56 except EntityNotExistsError: 

57 # Project needs to exist. 

58 return http_error( 

59 HTTPStatus.NOT_FOUND, 

60 'Project not found', 

61 f'Project with name {project_name} does not exist' 

62 ) 

63 return [skill.as_dict() for skill in all_skills] 

64 

65 @ns_conf.doc('create_skill') 

66 @api_endpoint_metrics('POST', '/skills') 

67 def post(self, project_name): 

68 '''Create a skill''' 

69 

70 # Check required request format. 

71 if 'skill' not in request.json: 

72 return http_error( 

73 HTTPStatus.BAD_REQUEST, 

74 'Missing parameter', 

75 'Must provide "skill" parameter in POST body' 

76 ) 

77 skill = request.json['skill'] 

78 return create_skill(project_name, skill) 

79 

80 

81@ns_conf.route('/<project_name>/skills/<skill_name>') 

82@ns_conf.param('project_name', 'Name of the project') 

83@ns_conf.param('skill_name', 'Name of the skill') 

84class SkillResource(Resource): 

85 @ns_conf.doc('get_skill') 

86 @api_endpoint_metrics('GET', '/skills/skill') 

87 def get(self, project_name, skill_name): 

88 '''Gets a skill by name''' 

89 skills_controller = SkillsController() 

90 try: 

91 existing_skill = skills_controller.get_skill(skill_name, project_name) 

92 except EntityNotExistsError: 

93 # Project needs to exist 

94 return http_error( 

95 HTTPStatus.NOT_FOUND, 

96 'Project not found', 

97 f'Project with name {project_name} does not exist' 

98 ) 

99 

100 if existing_skill is None: 

101 return http_error( 

102 HTTPStatus.NOT_FOUND, 

103 'Skill not found', 

104 f'Skill with name {skill_name} not found.' 

105 ) 

106 return existing_skill.as_dict() 

107 

108 @ns_conf.doc('update_skill') 

109 @api_endpoint_metrics('PUT', '/skills/skill') 

110 def put(self, project_name, skill_name): 

111 '''Updates a skill by name, creating one if it doesn't exist''' 

112 skills_controller = SkillsController() 

113 

114 # Check required request format. 

115 if 'skill' not in request.json: 

116 return http_error( 

117 HTTPStatus.BAD_REQUEST, 

118 'Missing parameter', 

119 'Must provide "skill" parameter in POST body' 

120 ) 

121 

122 try: 

123 existing_skill = skills_controller.get_skill(skill_name, project_name) 

124 except EntityNotExistsError: 

125 # Project needs to exist 

126 return http_error( 

127 HTTPStatus.NOT_FOUND, 

128 'Project not found', 

129 f'Project with name {project_name} does not exist' 

130 ) 

131 

132 skill = request.json['skill'] 

133 if existing_skill is None: 

134 # Use same name as provided in URL. 

135 skill['name'] = skill_name 

136 return create_skill(project_name, skill) 

137 

138 new_name = skill.get('name', None) 

139 new_type = skill.get('type', None) 

140 new_params = skill.get('params', None) 

141 updated_skill = skills_controller.update_skill( 

142 skill_name, 

143 new_name=new_name, 

144 project_name=project_name, 

145 type=new_type, 

146 params=new_params) 

147 return updated_skill.as_dict() 

148 

149 @ns_conf.doc('delete_skill') 

150 @api_endpoint_metrics('DELETE', '/skills/skill') 

151 def delete(self, project_name, skill_name): 

152 '''Deletes a skill by name''' 

153 skills_controller = SkillsController() 

154 try: 

155 existing_skill = skills_controller.get_skill(skill_name, project_name) 

156 except EntityNotExistsError: 

157 # Project needs to exist 

158 return http_error( 

159 HTTPStatus.NOT_FOUND, 

160 'Project not found', 

161 f'Project with name {project_name} does not exist' 

162 ) 

163 

164 if existing_skill is None: 

165 return http_error( 

166 HTTPStatus.NOT_FOUND, 

167 'Skill not found', 

168 f'Skill with name {skill_name} not found.' 

169 ) 

170 skills_controller.delete_skill(skill_name, project_name) 

171 return '', HTTPStatus.NO_CONTENT