Why cannot we have our cake and eat it too? Isn't there a way to have the import/export classes in a separate file that gets imported inside an import/export alias in the graph class so that G.export is actually GraphExporter(G, whatever) and tab completion works?
Partially related, ticket #9731 [1] might be relevant. http://trac.sagemath.org/sage_trac/ticket/9731 Cheers, J On Monday, July 9, 2012 4:03:55 AM UTC+1, Dima Pasechnik wrote: > > > > On Monday, 9 July 2012 10:22:31 UTC+8, Birk Eisermann wrote: >> >> Hello!! >> >> What is your opinion about improving the export and import of graphs? >> >> My conclusion of the sage-devel thread "Code duplication and aliases in >> methods" is that at the moment the source code in graph theory is not so >> optimal organized. As promised, I want to show some modifications that >> would lead to a better design. >> >> I found following members dealing with import or export of the class >> Graph. >> >> - returning a string to represent a graph: >> g.graph6_string, g.graphviz_string, g.dumps >> >> - export of a graph to a file >> g.graphviz_to_file_named, g.dump, g.save, g.db, (g.write_to_eps seems to >> involve g.plot) >> >> - import of a graph from a file >> none found?? Oh, they are hidden in the class constructors!! >> >> >> Including this functionality into the class Graph makes this class >> heavier and more difficult to understand - in my opinion (see the >> "single responsibility principle" [1]). Hence, I would create two >> separate classes for that. > > > this sacrifices a very important in interactive use feature: currently one > can create > an instance G of Graph and then > > sage: G.<hit 'Tab'> > > to see the methods of G. I understand that you are coming from a C++ > background where nothing like this is possible at all, but this is a very > quick and efficient way of looking up documentation without opening the > manual. > > Removing methods from Graph is removing them from this list of completions. > Ideally, as there are indeed too many methods in Graph, one might rather > think of having nested classes; then > sage: G.<hit 'Tab'> > would only show subclasses and immediate members: > > sage: class A: > ....: x=1 > ....: class B: > ....: y=2 > ....: > sage: a=A() > sage: a. # Tab was hit here > a.B a.x > sage: a.B.y # Tab was hit here, and produced unique completion, y > > Dima > > > >> Actually, there is no need to have pairs of >> import/export functions. Maybe one wants to read some special format >> only but does not need to write in that format. Or vice verse. Hence, I >> separate the import functions from the export ones. >> >> My approach uses static classes, that is, they contain no data and only >> member functions. For every programming task, there is only one instance >> which exports the graphs (and one for importing). Since we have two >> different types of graphs, Graph and Digraph, we need some case >> distinction... >> >> Some pseudo code about the classes - just to get the idea - hope you can >> understand :-) >> >> {{{ >> def GraphExporter: >> def graphviz(graph_object, filename, more_options) # calls >> helper functions according to type >> def _graphviz_Graph(graph_object, filename, more_options) >> def _graphviz_DiGraph(graph_object, filename, more_options) >> >> def sage_format(graph_object, filename, more_options) # calls >> helper functions according to type >> def _sage_format_Graph(graph_object, filename, more_options) >> def _sage_format_DiGraph(graph_object, filename, more_options) >> >> def graph6_string(graph_object) returns string >> def graphviz_string(graph_object) returns string >> >> def GraphImporter: >> def graphviz(filename, more_options) returns Graph_or_DiGraph_object >> def graphviz_get_type(filename, more_options) returns graph_type >> def _graphviz_Graph(filename, more_options) returns Graph_object >> def _graphviz_DiGraph(filename, more_options) returns DiGraph_object >> >> def sage_format(filename, more_options) returns (Di)Graph_object >> def sage_format_get_type(filename, more_options) returns graph_type >> def _sage_format_Graph(filename, more_options) returns Graph_object >> def _sage_format_DiGraph(filename, more_options) returns >> DiGraph_object >> >> def graph6_string(string) returns graph_object >> def graphviz_string(string) returns graph_object >> }}} >> >> Advantages of this design: >> + Adding a new import or export format is easier since the class >> Graph/DiGraph will not be touched. >> + The classes Graph and DiGraph will have less members. Files like >> graph.py and digraph.py will slightly lose weight... >> >> Disadvantage(s): >> - There is one more file and two more classes..., Anything else? >> >> >> Example code for reading unknown file and then write it in another >> format: >> {{{ >> GI = GraphImporter() >> G = GI.graphviz("/home/sage/myfile.viz") >> GraphExporter().sage_format(G, "/home/sage/myfile.sage") >> }}} >> >> What do you think about this approach? I might have overseen things >> since I am quite new to sage... >> >> Birk >> >> [1] https://en.wikipedia.org/wiki/Single_responsibility_principle >> > -- -- To post to this group, send an email to sage-devel@googlegroups.com To unsubscribe from this group, send an email to sage-devel+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/sage-devel URL: http://www.sagemath.org