@@ -90,7 +90,11 @@ def translate_dot_file(self, path: str) -> None:
9090 self ._raise_if_not_nx_importer ()
9191 raise_if_not_imported (dependency = pydot , dependency_name = "pydot" )
9292
93- graph = self ._normalize_dot_graph (nx .nx_pydot .read_dot (path ))
93+ pydot_graphs = pydot .graph_from_dot_file (path )
94+ if not pydot_graphs :
95+ raise ValueError ("Unable to parse DOT file." )
96+
97+ graph = self ._normalize_dot_graph (self ._graph_from_pydot (pydot_graphs [0 ]))
9498 self .translate (graph )
9599
96100 def translate_dot_data (self , dot_data : str ) -> None :
@@ -102,7 +106,7 @@ def translate_dot_data(self, dot_data: str) -> None:
102106 if not pydot_graphs :
103107 raise ValueError ("Unable to parse DOT data." )
104108
105- graph = self ._normalize_dot_graph (nx . nx_pydot . from_pydot (pydot_graphs [0 ]))
109+ graph = self ._normalize_dot_graph (self . _graph_from_pydot (pydot_graphs [0 ]))
106110 self .translate (graph )
107111
108112 def _raise_if_not_nx_importer (self ) -> None :
@@ -159,6 +163,45 @@ def _normalize_dot_graph(self, graph: nx.Graph) -> nx.Graph:
159163
160164 return normalized_graph
161165
166+ def _graph_from_pydot (self , dot_graph ) -> nx .MultiDiGraph :
167+ """Builds a MultiDiGraph from a pydot graph without using nx.nx_pydot."""
168+ graph = nx .MultiDiGraph ()
169+
170+ def _walk (current_graph ) -> None :
171+ for node in current_graph .get_nodes ():
172+ node_id = self ._normalize_dot_value (node .get_name ())
173+ # Ignore pydot/graphviz pseudo-nodes used for defaults.
174+ if node_id in {"" , "node" , "edge" , "graph" }:
175+ continue
176+
177+ properties = {
178+ self ._sanitize_property_key (key ): self ._normalize_dot_value (value )
179+ for key , value in (node .get_attributes () or {}).items ()
180+ }
181+ if node_id in graph .nodes :
182+ graph .nodes [node_id ].update (properties )
183+ else :
184+ graph .add_node (node_id , ** properties )
185+
186+ for edge in current_graph .get_edges ():
187+ source = self ._normalize_dot_value (edge .get_source ())
188+ dest = self ._normalize_dot_value (edge .get_destination ())
189+ if not source or not dest :
190+ continue
191+
192+ properties = {
193+ self ._sanitize_property_key (key ): self ._normalize_dot_value (value )
194+ for key , value in (edge .get_attributes () or {}).items ()
195+ }
196+ graph .add_edge (source , dest , ** properties )
197+
198+ for subgraph in current_graph .get_subgraphs ():
199+ _walk (subgraph )
200+
201+ _walk (dot_graph )
202+
203+ return graph
204+
162205 def _normalize_dot_properties (self , properties : Dict [str , Any ]) -> Dict [str , Any ]:
163206 normalized_attributes = {
164207 self ._sanitize_property_key (key ): self ._normalize_dot_value (value ) for key , value in properties .items ()
0 commit comments