Coverage for tests/test_project.py: 100%

109 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-01 22:07 +0000

1import numpy as np 

2import peprs 

3import pytest 

4 

5from pepdbagent.exceptions import ProjectNotFoundError 

6 

7from .utils import ( 

8 PEPDBAgentContextManager, 

9 get_path_to_example_file, 

10 list_of_available_peps, 

11) 

12 

13 

14@pytest.mark.skipif( 

15 not PEPDBAgentContextManager().db_setup(), 

16 reason="DB is not setup", 

17) 

18class TestProject: 

19 """ 

20 Test project methods 

21 """ 

22 

23 def test_create_project(self): 

24 with PEPDBAgentContextManager(add_data=False) as agent: 

25 prj = peprs.Project(list_of_available_peps()["namespace3"]["subtables"]) 

26 agent.project.create(prj, namespace="test", name="imply", overwrite=False) 

27 assert True 

28 

29 def test_create_project_from_dict(self): 

30 with PEPDBAgentContextManager(add_data=False) as agent: 

31 prj = peprs.Project(list_of_available_peps()["namespace3"]["subtables"]) 

32 agent.project.create( 

33 prj.to_dict(raw=True, by_sample=True), 

34 namespace="test", 

35 name="imply", 

36 overwrite=True, 

37 ) 

38 assert True 

39 

40 @pytest.mark.parametrize( 

41 "namespace, name", 

42 [ 

43 ["namespace1", "amendments1"], 

44 ["namespace1", "amendments2"], 

45 ["namespace1", "basic"], 

46 ["namespace2", "derive"], 

47 ["namespace2", "imply"], 

48 ["namespace3", "piface"], 

49 ["namespace3", "subtable2"], 

50 ], 

51 ) 

52 def test_get_project(self, namespace, name): 

53 with PEPDBAgentContextManager(add_data=True) as agent: 

54 kk = agent.project.get( 

55 namespace=namespace, name=name, tag="default", raw=True 

56 ) 

57 ff = peprs.Project(get_path_to_example_file(namespace, name)).to_dict( 

58 raw=True, by_sample=True 

59 ) 

60 # pepdbagent always sets the registry name on the stored config, 

61 # overriding any name in the file (which may be empty or different). 

62 ff["config"]["name"] = name 

63 assert kk["config"] == ff["config"] 

64 assert kk["samples"] == ff["samples"] 

65 assert kk.get("subsamples", []) == ff.get("subsamples", []) 

66 

67 @pytest.mark.parametrize( 

68 "namespace, name", 

69 [ 

70 ["namespace1", "amendments1"], 

71 ], 

72 ) 

73 def test_get_config(self, namespace, name): 

74 with PEPDBAgentContextManager(add_data=True) as agent: 

75 description = "" 

76 kk = agent.project.get_config( 

77 namespace=namespace, 

78 name=name, 

79 tag="default", 

80 ) 

81 ff = peprs.Project(get_path_to_example_file(namespace, name)) 

82 expected_config = ff.config.copy() 

83 expected_config["description"] = description 

84 expected_config["name"] = name 

85 assert kk == expected_config 

86 

87 @pytest.mark.parametrize( 

88 "namespace, name", 

89 [ 

90 ["namespace3", "subtables"], 

91 ], 

92 ) 

93 def test_get_subsamples(self, namespace, name): 

94 with PEPDBAgentContextManager(add_data=True) as agent: 

95 prj_subtables = agent.project.get_subsamples( 

96 namespace=namespace, 

97 name=name, 

98 tag="default", 

99 ) 

100 orgiginal_prj = peprs.Project(get_path_to_example_file(namespace, name)) 

101 

102 assert ( 

103 prj_subtables 

104 == orgiginal_prj.to_dict(raw=True, by_sample=True)["subsamples"] 

105 ) 

106 

107 @pytest.mark.parametrize( 

108 "namespace, name", 

109 [ 

110 ["namespace3", "subtables"], 

111 ], 

112 ) 

113 def test_get_samples_raw(self, namespace, name): 

114 with PEPDBAgentContextManager(add_data=True) as agent: 

115 prj_samples = agent.project.get_samples( 

116 namespace=namespace, name=name, tag="default", raw=True 

117 ) 

118 orgiginal_prj = peprs.Project(get_path_to_example_file(namespace, name)) 

119 

120 assert ( 

121 prj_samples 

122 == orgiginal_prj.to_dict(raw=True, by_sample=True)["samples"] 

123 ) 

124 

125 @pytest.mark.parametrize( 

126 "namespace, name", 

127 [ 

128 ["namespace3", "subtables"], 

129 ], 

130 ) 

131 def test_get_samples_processed(self, namespace, name): 

132 with PEPDBAgentContextManager(add_data=True) as agent: 

133 prj_samples = agent.project.get_samples( 

134 namespace=namespace, 

135 name=name, 

136 tag="default", 

137 raw=False, 

138 ) 

139 orgiginal_prj = peprs.Project(get_path_to_example_file(namespace, name)) 

140 expected = ( 

141 orgiginal_prj.to_pandas() 

142 .replace({np.nan: None}) 

143 .to_dict(orient="records") 

144 ) 

145 

146 # Normalize numpy arrays (used for subsample list columns) to plain lists 

147 # so dict equality works without raising "truth value is ambiguous". 

148 def _normalize(samples): 

149 return [ 

150 { 

151 k: (v.tolist() if isinstance(v, np.ndarray) else v) 

152 for k, v in s.items() 

153 } 

154 for s in samples 

155 ] 

156 

157 assert _normalize(prj_samples) == _normalize(expected) 

158 

159 @pytest.mark.parametrize( 

160 "namespace, name,tag", 

161 [ 

162 ["incorrect_namespace", "amendments1", "default"], 

163 ["namespace1", "subtable2", "default"], 

164 ["namespace3", "basic", "default"], 

165 ["namespace3", "subtable2", "incorrect_tag"], 

166 ["namespace1", "incorrect_name", "default"], 

167 ], 

168 ) 

169 def test_get_project_error(self, namespace, name, tag): 

170 with PEPDBAgentContextManager(add_data=True) as agent: 

171 with pytest.raises(ProjectNotFoundError, match="Project does not exist."): 

172 agent.project.get(namespace=namespace, name=name, tag=tag) 

173 

174 @pytest.mark.parametrize( 

175 "namespace, name", 

176 [ 

177 ["namespace1", "amendments1"], 

178 ["namespace1", "amendments2"], 

179 ["namespace2", "derive"], 

180 ["namespace2", "imply"], 

181 ], 

182 ) 

183 def test_overwrite_project(self, namespace, name): 

184 with PEPDBAgentContextManager(add_data=True) as agent: 

185 new_prj = agent.project.get(namespace="namespace1", name="basic", raw=False) 

186 

187 agent.project.create( 

188 project=new_prj, 

189 namespace=namespace, 

190 name=name, 

191 tag="default", 

192 overwrite=True, 

193 ) 

194 

195 assert ( 

196 agent.project.get(namespace=namespace, name=name, raw=False) == new_prj 

197 ) 

198 

199 @pytest.mark.parametrize( 

200 "namespace, name", 

201 [ 

202 ["namespace1", "amendments1"], 

203 ["namespace2", "derive"], 

204 ], 

205 ) 

206 def test_delete_project(self, namespace, name): 

207 with PEPDBAgentContextManager(add_data=True) as agent: 

208 agent.project.delete(namespace=namespace, name=name, tag="default") 

209 

210 with pytest.raises(ProjectNotFoundError, match="Project does not exist."): 

211 agent.project.get(namespace=namespace, name=name, tag="default") 

212 

213 def test_delete_not_existing_project(self): 

214 with PEPDBAgentContextManager(add_data=True) as agent: 

215 with pytest.raises(ProjectNotFoundError, match="Project does not exist."): 

216 agent.project.delete( 

217 namespace="namespace1", name="nothing", tag="default" 

218 ) 

219 

220 @pytest.mark.parametrize( 

221 "namespace, name", 

222 [ 

223 ["namespace1", "amendments2"], 

224 ["namespace2", "derive"], 

225 ["namespace2", "imply"], 

226 ], 

227 ) 

228 def test_fork_projects(self, namespace, name): 

229 with PEPDBAgentContextManager(add_data=True) as agent: 

230 agent.project.fork( 

231 original_namespace=namespace, 

232 original_name=name, 

233 original_tag="default", 

234 fork_namespace="new_namespace", 

235 fork_name="new_name", 

236 fork_tag="new_tag", 

237 ) 

238 

239 assert agent.project.exists( 

240 namespace="new_namespace", name="new_name", tag="new_tag" 

241 ) 

242 result = agent.annotation.get( 

243 namespace="new_namespace", name="new_name", tag="new_tag" 

244 ) 

245 assert result.results[0].forked_from == f"{namespace}/{name}:default" 

246 

247 @pytest.mark.parametrize( 

248 "namespace, name", 

249 [ 

250 ["namespace1", "amendments1"], 

251 ["namespace1", "amendments2"], 

252 ], 

253 ) 

254 def test_parent_project_delete(self, namespace, name): 

255 """ 

256 Test if parent project is deleted, forked project is not deleted 

257 """ 

258 with PEPDBAgentContextManager(add_data=True) as agent: 

259 agent.project.fork( 

260 original_namespace=namespace, 

261 original_name=name, 

262 original_tag="default", 

263 fork_namespace="new_namespace", 

264 fork_name="new_name", 

265 fork_tag="new_tag", 

266 ) 

267 

268 assert agent.project.exists( 

269 namespace="new_namespace", name="new_name", tag="new_tag" 

270 ) 

271 agent.project.delete(namespace=namespace, name=name, tag="default") 

272 assert agent.project.exists( 

273 namespace="new_namespace", name="new_name", tag="new_tag" 

274 ) 

275 

276 @pytest.mark.parametrize( 

277 "namespace, name", 

278 [ 

279 ["namespace1", "amendments1"], 

280 ["namespace1", "amendments2"], 

281 ], 

282 ) 

283 def test_child_project_delete(self, namespace, name): 

284 """ 

285 Test if child project is deleted, parent project is not deleted 

286 """ 

287 with PEPDBAgentContextManager(add_data=True) as agent: 

288 agent.project.fork( 

289 original_namespace=namespace, 

290 original_name=name, 

291 original_tag="default", 

292 fork_namespace="new_namespace", 

293 fork_name="new_name", 

294 fork_tag="new_tag", 

295 ) 

296 

297 assert agent.project.exists( 

298 namespace="new_namespace", name="new_name", tag="new_tag" 

299 ) 

300 assert agent.project.exists(namespace=namespace, name=name, tag="default") 

301 agent.project.delete( 

302 namespace="new_namespace", name="new_name", tag="new_tag" 

303 ) 

304 assert agent.project.exists(namespace=namespace, name=name, tag="default") 

305 

306 @pytest.mark.parametrize( 

307 "namespace, name", 

308 [ 

309 ["namespace1", "amendments1"], 

310 ["namespace1", "amendments2"], 

311 ], 

312 ) 

313 def test_project_can_be_forked_twice(self, namespace, name): 

314 """ 

315 Test if project can be forked twice 

316 """ 

317 with PEPDBAgentContextManager(add_data=True) as agent: 

318 agent.project.fork( 

319 original_namespace=namespace, 

320 original_name=name, 

321 original_tag="default", 

322 fork_namespace="new_namespace", 

323 fork_name="new_name", 

324 fork_tag="new_tag", 

325 ) 

326 agent.project.fork( 

327 original_namespace=namespace, 

328 original_name=name, 

329 original_tag="default", 

330 fork_namespace="new_namespace2", 

331 fork_name="new_name2", 

332 fork_tag="new_tag2", 

333 ) 

334 

335 result = agent.annotation.get( 

336 namespace="new_namespace", name="new_name", tag="new_tag" 

337 ) 

338 assert result.results[0].forked_from == f"{namespace}/{name}:default" 

339 

340 result = agent.annotation.get( 

341 namespace="new_namespace2", name="new_name2", tag="new_tag2" 

342 ) 

343 assert result.results[0].forked_from == f"{namespace}/{name}:default"