Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/networkx/readwrite/multiline_adjlist.py: 10%

111 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-10-20 07:00 +0000

1""" 

2************************* 

3Multi-line Adjacency List 

4************************* 

5Read and write NetworkX graphs as multi-line adjacency lists. 

6 

7The multi-line adjacency list format is useful for graphs with 

8nodes that can be meaningfully represented as strings. With this format 

9simple edge data can be stored but node or graph data is not. 

10 

11Format 

12------ 

13The first label in a line is the source node label followed by the node degree 

14d. The next d lines are target node labels and optional edge data. 

15That pattern repeats for all nodes in the graph. 

16 

17The graph with edges a-b, a-c, d-e can be represented as the following 

18adjacency list (anything following the # in a line is a comment):: 

19 

20 # example.multiline-adjlist 

21 a 2 

22 b 

23 c 

24 d 1 

25 e 

26""" 

27 

28__all__ = [ 

29 "generate_multiline_adjlist", 

30 "write_multiline_adjlist", 

31 "parse_multiline_adjlist", 

32 "read_multiline_adjlist", 

33] 

34 

35import networkx as nx 

36from networkx.utils import open_file 

37 

38 

39def generate_multiline_adjlist(G, delimiter=" "): 

40 """Generate a single line of the graph G in multiline adjacency list format. 

41 

42 Parameters 

43 ---------- 

44 G : NetworkX graph 

45 

46 delimiter : string, optional 

47 Separator for node labels 

48 

49 Returns 

50 ------- 

51 lines : string 

52 Lines of data in multiline adjlist format. 

53 

54 Examples 

55 -------- 

56 >>> G = nx.lollipop_graph(4, 3) 

57 >>> for line in nx.generate_multiline_adjlist(G): 

58 ... print(line) 

59 0 3 

60 1 {} 

61 2 {} 

62 3 {} 

63 1 2 

64 2 {} 

65 3 {} 

66 2 1 

67 3 {} 

68 3 1 

69 4 {} 

70 4 1 

71 5 {} 

72 5 1 

73 6 {} 

74 6 0 

75 

76 See Also 

77 -------- 

78 write_multiline_adjlist, read_multiline_adjlist 

79 """ 

80 if G.is_directed(): 

81 if G.is_multigraph(): 

82 for s, nbrs in G.adjacency(): 

83 nbr_edges = [ 

84 (u, data) 

85 for u, datadict in nbrs.items() 

86 for key, data in datadict.items() 

87 ] 

88 deg = len(nbr_edges) 

89 yield str(s) + delimiter + str(deg) 

90 for u, d in nbr_edges: 

91 if d is None: 

92 yield str(u) 

93 else: 

94 yield str(u) + delimiter + str(d) 

95 else: # directed single edges 

96 for s, nbrs in G.adjacency(): 

97 deg = len(nbrs) 

98 yield str(s) + delimiter + str(deg) 

99 for u, d in nbrs.items(): 

100 if d is None: 

101 yield str(u) 

102 else: 

103 yield str(u) + delimiter + str(d) 

104 else: # undirected 

105 if G.is_multigraph(): 

106 seen = set() # helper dict used to avoid duplicate edges 

107 for s, nbrs in G.adjacency(): 

108 nbr_edges = [ 

109 (u, data) 

110 for u, datadict in nbrs.items() 

111 if u not in seen 

112 for key, data in datadict.items() 

113 ] 

114 deg = len(nbr_edges) 

115 yield str(s) + delimiter + str(deg) 

116 for u, d in nbr_edges: 

117 if d is None: 

118 yield str(u) 

119 else: 

120 yield str(u) + delimiter + str(d) 

121 seen.add(s) 

122 else: # undirected single edges 

123 seen = set() # helper dict used to avoid duplicate edges 

124 for s, nbrs in G.adjacency(): 

125 nbr_edges = [(u, d) for u, d in nbrs.items() if u not in seen] 

126 deg = len(nbr_edges) 

127 yield str(s) + delimiter + str(deg) 

128 for u, d in nbr_edges: 

129 if d is None: 

130 yield str(u) 

131 else: 

132 yield str(u) + delimiter + str(d) 

133 seen.add(s) 

134 

135 

136@open_file(1, mode="wb") 

137def write_multiline_adjlist(G, path, delimiter=" ", comments="#", encoding="utf-8"): 

138 """Write the graph G in multiline adjacency list format to path 

139 

140 Parameters 

141 ---------- 

142 G : NetworkX graph 

143 

144 path : string or file 

145 Filename or file handle to write to. 

146 Filenames ending in .gz or .bz2 will be compressed. 

147 

148 comments : string, optional 

149 Marker for comment lines 

150 

151 delimiter : string, optional 

152 Separator for node labels 

153 

154 encoding : string, optional 

155 Text encoding. 

156 

157 Examples 

158 -------- 

159 >>> G = nx.path_graph(4) 

160 >>> nx.write_multiline_adjlist(G, "test.adjlist") 

161 

162 The path can be a file handle or a string with the name of the file. If a 

163 file handle is provided, it has to be opened in 'wb' mode. 

164 

165 >>> fh = open("test.adjlist", "wb") 

166 >>> nx.write_multiline_adjlist(G, fh) 

167 

168 Filenames ending in .gz or .bz2 will be compressed. 

169 

170 >>> nx.write_multiline_adjlist(G, "test.adjlist.gz") 

171 

172 See Also 

173 -------- 

174 read_multiline_adjlist 

175 """ 

176 import sys 

177 import time 

178 

179 pargs = comments + " ".join(sys.argv) 

180 header = ( 

181 f"{pargs}\n" 

182 + comments 

183 + f" GMT {time.asctime(time.gmtime())}\n" 

184 + comments 

185 + f" {G.name}\n" 

186 ) 

187 path.write(header.encode(encoding)) 

188 

189 for multiline in generate_multiline_adjlist(G, delimiter): 

190 multiline += "\n" 

191 path.write(multiline.encode(encoding)) 

192 

193 

194@nx._dispatch(graphs=None) 

195def parse_multiline_adjlist( 

196 lines, comments="#", delimiter=None, create_using=None, nodetype=None, edgetype=None 

197): 

198 """Parse lines of a multiline adjacency list representation of a graph. 

199 

200 Parameters 

201 ---------- 

202 lines : list or iterator of strings 

203 Input data in multiline adjlist format 

204 

205 create_using : NetworkX graph constructor, optional (default=nx.Graph) 

206 Graph type to create. If graph instance, then cleared before populated. 

207 

208 nodetype : Python type, optional 

209 Convert nodes to this type. 

210 

211 edgetype : Python type, optional 

212 Convert edges to this type. 

213 

214 comments : string, optional 

215 Marker for comment lines 

216 

217 delimiter : string, optional 

218 Separator for node labels. The default is whitespace. 

219 

220 Returns 

221 ------- 

222 G: NetworkX graph 

223 The graph corresponding to the lines in multiline adjacency list format. 

224 

225 Examples 

226 -------- 

227 >>> lines = [ 

228 ... "1 2", 

229 ... "2 {'weight':3, 'name': 'Frodo'}", 

230 ... "3 {}", 

231 ... "2 1", 

232 ... "5 {'weight':6, 'name': 'Saruman'}", 

233 ... ] 

234 >>> G = nx.parse_multiline_adjlist(iter(lines), nodetype=int) 

235 >>> list(G) 

236 [1, 2, 3, 5] 

237 

238 """ 

239 from ast import literal_eval 

240 

241 G = nx.empty_graph(0, create_using) 

242 for line in lines: 

243 p = line.find(comments) 

244 if p >= 0: 

245 line = line[:p] 

246 if not line: 

247 continue 

248 try: 

249 (u, deg) = line.strip().split(delimiter) 

250 deg = int(deg) 

251 except BaseException as err: 

252 raise TypeError(f"Failed to read node and degree on line ({line})") from err 

253 if nodetype is not None: 

254 try: 

255 u = nodetype(u) 

256 except BaseException as err: 

257 raise TypeError( 

258 f"Failed to convert node ({u}) to " f"type {nodetype}" 

259 ) from err 

260 G.add_node(u) 

261 for i in range(deg): 

262 while True: 

263 try: 

264 line = next(lines) 

265 except StopIteration as err: 

266 msg = f"Failed to find neighbor for node ({u})" 

267 raise TypeError(msg) from err 

268 p = line.find(comments) 

269 if p >= 0: 

270 line = line[:p] 

271 if line: 

272 break 

273 vlist = line.strip().split(delimiter) 

274 numb = len(vlist) 

275 if numb < 1: 

276 continue # isolated node 

277 v = vlist.pop(0) 

278 data = "".join(vlist) 

279 if nodetype is not None: 

280 try: 

281 v = nodetype(v) 

282 except BaseException as err: 

283 raise TypeError( 

284 f"Failed to convert node ({v}) " f"to type {nodetype}" 

285 ) from err 

286 if edgetype is not None: 

287 try: 

288 edgedata = {"weight": edgetype(data)} 

289 except BaseException as err: 

290 raise TypeError( 

291 f"Failed to convert edge data ({data}) " f"to type {edgetype}" 

292 ) from err 

293 else: 

294 try: # try to evaluate 

295 edgedata = literal_eval(data) 

296 except: 

297 edgedata = {} 

298 G.add_edge(u, v, **edgedata) 

299 

300 return G 

301 

302 

303@open_file(0, mode="rb") 

304@nx._dispatch(graphs=None) 

305def read_multiline_adjlist( 

306 path, 

307 comments="#", 

308 delimiter=None, 

309 create_using=None, 

310 nodetype=None, 

311 edgetype=None, 

312 encoding="utf-8", 

313): 

314 """Read graph in multi-line adjacency list format from path. 

315 

316 Parameters 

317 ---------- 

318 path : string or file 

319 Filename or file handle to read. 

320 Filenames ending in .gz or .bz2 will be uncompressed. 

321 

322 create_using : NetworkX graph constructor, optional (default=nx.Graph) 

323 Graph type to create. If graph instance, then cleared before populated. 

324 

325 nodetype : Python type, optional 

326 Convert nodes to this type. 

327 

328 edgetype : Python type, optional 

329 Convert edge data to this type. 

330 

331 comments : string, optional 

332 Marker for comment lines 

333 

334 delimiter : string, optional 

335 Separator for node labels. The default is whitespace. 

336 

337 Returns 

338 ------- 

339 G: NetworkX graph 

340 

341 Examples 

342 -------- 

343 >>> G = nx.path_graph(4) 

344 >>> nx.write_multiline_adjlist(G, "test.adjlist") 

345 >>> G = nx.read_multiline_adjlist("test.adjlist") 

346 

347 The path can be a file or a string with the name of the file. If a 

348 file s provided, it has to be opened in 'rb' mode. 

349 

350 >>> fh = open("test.adjlist", "rb") 

351 >>> G = nx.read_multiline_adjlist(fh) 

352 

353 Filenames ending in .gz or .bz2 will be compressed. 

354 

355 >>> nx.write_multiline_adjlist(G, "test.adjlist.gz") 

356 >>> G = nx.read_multiline_adjlist("test.adjlist.gz") 

357 

358 The optional nodetype is a function to convert node strings to nodetype. 

359 

360 For example 

361 

362 >>> G = nx.read_multiline_adjlist("test.adjlist", nodetype=int) 

363 

364 will attempt to convert all nodes to integer type. 

365 

366 The optional edgetype is a function to convert edge data strings to 

367 edgetype. 

368 

369 >>> G = nx.read_multiline_adjlist("test.adjlist") 

370 

371 The optional create_using parameter is a NetworkX graph container. 

372 The default is Graph(), an undirected graph. To read the data as 

373 a directed graph use 

374 

375 >>> G = nx.read_multiline_adjlist("test.adjlist", create_using=nx.DiGraph) 

376 

377 Notes 

378 ----- 

379 This format does not store graph, node, or edge data. 

380 

381 See Also 

382 -------- 

383 write_multiline_adjlist 

384 """ 

385 lines = (line.decode(encoding) for line in path) 

386 return parse_multiline_adjlist( 

387 lines, 

388 comments=comments, 

389 delimiter=delimiter, 

390 create_using=create_using, 

391 nodetype=nodetype, 

392 edgetype=edgetype, 

393 )