[geneagrapher] 10/226: Implemented Geneagrapher class, which allows the tool to be used from the command line to produce "ancestor graphs". This resolves ticket #6.

Doug Torrance dtorrance-guest at moszumanska.debian.org
Sat Jul 11 17:10:31 UTC 2015


This is an automated email from the git hooks/post-receive script.

dtorrance-guest pushed a commit to branch master
in repository geneagrapher.

commit c72325824089e56f7dca2724aed2f9395a3e8c28
Author: David Alber <alber.david at gmail.com>
Date:   Sat May 3 04:18:18 2008 +0000

    Implemented Geneagrapher class, which allows the tool to be used from the command line to produce "ancestor graphs". This resolves ticket #6.
---
 src/GGraph.py       | 50 +++++++++++++++++++++++++++++---------------------
 src/geneagrapher.py | 35 +++++++++++++++++++++++++----------
 src/tests.py        | 44 ++++++++++++++++++++++++++------------------
 3 files changed, 80 insertions(+), 49 deletions(-)

diff --git a/src/GGraph.py b/src/GGraph.py
index 1123fef..3b5186a 100644
--- a/src/GGraph.py
+++ b/src/GGraph.py
@@ -27,9 +27,9 @@ class Record:
         # Verify we got the types wanted.
         if not isinstance(self.name, basestring):
             raise TypeError("Unexpected parameter type: expected string value for 'name'")
-        if not isinstance(self.institution, basestring):
+        if not isinstance(self.institution, basestring) and self.institution is not None:
             raise TypeError("Unexpected parameter type: expected string value for 'institution'")
-        if not isinstance(self.year, int):
+        if not isinstance(self.year, int) and self.year is not None:
             raise TypeError("Unexpected parameter type: expected integer value for 'year'")
         if not isinstance(self.id, int):
             raise TypeError("Unexpected parameter type: expected integer value for 'id'")
@@ -45,14 +45,14 @@ class Record:
         Return True if this record has an institution associated with it,
         else False.
         """
-        return self.institution != ""
+        return self.institution is not None
     
     def hasYear(self):
         """
         Return True if this record has a year associated with it, else
         False.
         """
-        return self.year != -1
+        return self.year is not None
     
 
 class Node:
@@ -114,24 +114,28 @@ class Graph:
     """
     Class storing the representation of a genealogy graph.
     """
-    def __init__(self, head=None):
+    def __init__(self, heads=None):
         """
         Graph class constructor.
         
         Parameters:
-            head: a Node object representing the tree head (can be
-                omitted to create an empty graph)
+            heads: a list of Node objects representing the tree head
+                (can be omitted to create an empty graph)
         """
-        self.head = head
+        self.heads = heads
         
-        # Verify type of head is what we expect.
-        if self.head is not None and not isinstance(self.head, Node):
-            raise TypeError("Unexpected parameter type: expected Node object for 'head'")
-
-        if self.head is not None:
-            self.nodes = {head.id(): head}
-        else:
-            self.nodes = {}
+        # Verify type of heads is what we expect.
+        if self.heads is not None:
+            if not isinstance(self.heads, list):
+                raise TypeError("Unexpected parameter type: expected list of Node objects for 'heads'")
+            for head in self.heads:
+                if not isinstance(head, Node):
+                    raise TypeError("Unexpected parameter type: expected list of Node objects for 'heads'")
+
+        self.nodes = {}
+        if self.heads is not None:
+            for head in self.heads:
+                self.nodes[head.id()] = head
 
     def hasNode(self, id):
         """
@@ -155,7 +159,7 @@ class Graph:
         """
         return self.nodes.keys()
 
-    def addNode(self, name, institution, year, id, ancestors):
+    def addNode(self, name, institution, year, id, ancestors, isHead=False):
         """
         Add a new node to the graph if a matching node is not already
         present.
@@ -164,8 +168,10 @@ class Graph:
             record = Record(name, institution, year, id)
             node = Node(record, ancestors)
             self.nodes[id] = node
-            if self.head is None:
-                self.head = node
+            if self.heads is None:
+                self.heads = [node]
+            elif isHead:
+                self.heads.append(node)
         else:
             msg = "node with id %d already exists" % (id)
             raise DuplicateNodeError(msg)
@@ -175,10 +181,12 @@ class Graph:
         Return a string that contains the content of the Graphviz dotfile
         format for this graph.
         """
-        if self.head is None:
+        if self.heads is None:
             return ""
 
-        queue = [self.head.id()]
+        queue = []
+        for head in self.heads:
+            queue.append(head.id())
         edges = ""
         dotfile = ""
         
diff --git a/src/geneagrapher.py b/src/geneagrapher.py
index f54d478..c142f36 100644
--- a/src/geneagrapher.py
+++ b/src/geneagrapher.py
@@ -12,6 +12,7 @@ class Geneagrapher:
 		self.leaf_ids = []
 		self.get_ancestors = True
 		self.get_descendents = False
+		self.verbose = False
 		self.write_filename = None
 
 	def parseInput(self):
@@ -23,20 +24,29 @@ class Geneagrapher:
 		self.parser.set_usage("%prog [options] ID ...")
 		self.parser.set_description('Create a Graphviz "dot" file for a mathematics genealogy, where ID is a record identifier from the Mathematics Genealogy Project. Multiple IDs may be passed.')
 
-		self.parser.add_option("-f", "--file", dest="filename", help="write report to FILE [default: stdout]",
-							   metavar="FILE", default=None)
-		self.parser.add_option("--without-ancestors", action="store_false", dest="get_ancestors", default=True,
-						  help="do not get ancestors of any input IDs")
-		self.parser.add_option("--with-descendents", action="store_true", dest="get_descendents", default=False,
-						  help="do not get ancestors of any input IDs")
+		self.parser.add_option("-f", "--file", dest="filename",
+				       help="write report to FILE [default: stdout]", metavar="FILE", default=None)
+		self.parser.add_option("--without-ancestors", action="store_false", dest="get_ancestors",
+				       default=True, help="do not get ancestors of any input IDs")
+		self.parser.add_option("--with-descendents", action="store_true", dest="get_descendents",
+				       default=False, help="do not get ancestors of any input IDs")
+		self.parser.add_option("--verbose", "-v", action="store_true", dest="verbose", default=False,
+				       help="print information showing progress")
+		self.parser.add_option("--version", "-V", action="store_true", dest="print_version", default=False,
+				       help="print geneagrapher version and exit")
 
 		(options, args) = self.parser.parse_args()
 		
+		if options.print_version:
+			print "Geneagrapher Version 0.2"
+			self.parser.exit()
+		
 		if len(args) == 0:
 			raise SyntaxError("%s: error: no record IDs passed" % (self.parser.get_prog_name()))
-		
+
 		self.get_ancestors = options.get_ancestors
 		self.get_descendents = options.get_descendents
+		self.verbose = options.verbose
 		self.write_filename = options.filename
 		for arg in args:
 			self.leaf_ids.append(int(arg))
@@ -46,18 +56,23 @@ class Geneagrapher:
 		Populate the graph member by grabbing the mathematician
 		pages and extracting relevant data.
 		"""
-		grab_queue = self.leaf_ids
+		grab_queue = list(self.leaf_ids)
 		while len(grab_queue) != 0:
 			id = grab_queue.pop()
 			if not self.graph.hasNode(id):
 				# Then this information has not yet been grabbed.
 				grabber = grab.Grabber(id)
+				if self.verbose:
+					print "Grabbing record #%d" % (id)
 				try:
 					[name, institution, year, advisors] = grabber.extractNodeInformation()
 				except ValueError:
 					# The given id does not exist in the Math Genealogy Project's database.
 					raise
-				self.graph.addNode(name, institution, year, id, advisors)
+				if id in self.leaf_ids:
+					self.graph.addNode(name, institution, year, id, advisors, True)
+				else:
+					self.graph.addNode(name, institution, year, id, advisors)
 				if self.get_ancestors:
 					grab_queue += advisors
 					
@@ -78,4 +93,4 @@ if __name__ == "__main__":
 		print geneagrapher.parser.get_usage()
 		print e
 	geneagrapher.buildGraph()
-	geneagrapher.generateDotFile()
\ No newline at end of file
+	geneagrapher.generateDotFile()
diff --git a/src/tests.py b/src/tests.py
index 06e8119..15abc32 100644
--- a/src/tests.py
+++ b/src/tests.py
@@ -52,9 +52,9 @@ class TestRecordMethods(unittest.TestCase):
         record = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231)
         self.assert_(record.hasInstitution())
 
-    def test009_hasInstitution_yes(self):
+    def test009_hasInstitution_no(self):
         # Verify hasInstitution() method returns False when the conditions are right.
-        record = GGraph.Record("Carl Friedrich Gauss", "", 1799, 18231)
+        record = GGraph.Record("Carl Friedrich Gauss", None, 1799, 18231)
         self.assert_(not record.hasInstitution())
 
     def test010_hasYear_yes(self):
@@ -64,7 +64,7 @@ class TestRecordMethods(unittest.TestCase):
 
     def test011_hasYear_no(self):
         # Verify hasYear() method returns False when the conditions are right.
-        record = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", -1, 18231)
+        record = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", None, 18231)
         self.assert_(not record.hasYear())
 
 class TestNodeMethods(unittest.TestCase):
@@ -98,7 +98,7 @@ class TestNodeMethods(unittest.TestCase):
 
     def test005_str_no_year(self):
         # Test __str__() method for Node containing record without year.
-        record = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", -1, 18231)
+        record = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", None, 18231)
         node = GGraph.Node(record, [])
         nodestr = node.__str__()
         nodestrexpt = "Carl Friedrich Gauss \\nUniversitaet Helmstedt"
@@ -106,7 +106,7 @@ class TestNodeMethods(unittest.TestCase):
 
     def test006_str_no_inst(self):
         # Test __str__() method for Node containing record without institution.
-        record = GGraph.Record("Carl Friedrich Gauss", "", 1799, 18231)
+        record = GGraph.Record("Carl Friedrich Gauss", None, 1799, 18231)
         node = GGraph.Node(record, [])
         nodestr = node.__str__()
         nodestrexpt = "Carl Friedrich Gauss \\n(1799)"
@@ -115,7 +115,7 @@ class TestNodeMethods(unittest.TestCase):
     def test007_str_no_inst_no_id(self):
         # Test __str__() method for Node containing record without institution
         # or year.
-        record = GGraph.Record("Carl Friedrich Gauss", "", -1, 18231)
+        record = GGraph.Record("Carl Friedrich Gauss", None, None, 18231)
         node = GGraph.Node(record, [])
         nodestr = node.__str__()
         nodestrexpt = "Carl Friedrich Gauss"
@@ -157,21 +157,21 @@ class TestGraphMethods(unittest.TestCase):
     def setUp(self):
         self.record1 = GGraph.Record("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231)
         self.node1 = GGraph.Node(self.record1, [])
-        self.graph1 = GGraph.Graph(self.node1)
+        self.graph1 = GGraph.Graph([self.node1])
     
     def test001_init_empty(self):
         # Test the constructor.
         graph = GGraph.Graph()
-        self.assertEquals(graph.head, None)
+        self.assertEquals(graph.heads, None)
         
     def test002_init(self):
         # Test the constructor.
-        self.assert_(self.graph1.head == self.node1)
+        self.assert_(self.graph1.heads == [self.node1])
         self.assertEquals(self.graph1.nodes.keys(), [18231])
         self.assertEquals(self.graph1.nodes[18231], self.node1)
         
-    def test003_init_bad_head(self):
-        # Test the constructor when passed a bad type for the head parameter.
+    def test003_init_bad_heads(self):
+        # Test the constructor when passed a bad type for the heads parameter.
         self.assertRaises(TypeError, GGraph.Graph, 3)
         
     def test004_has_node_true(self):
@@ -205,20 +205,28 @@ class TestGraphMethods(unittest.TestCase):
         # Test the addNode() method.
         self.graph1.addNode("Leonhard Euler", "Universitaet Basel", 1726, 38586, [])
         self.assertEquals([38586, 18231], self.graph1.getNodeList())
+        self.assertEquals(self.graph1.heads, [self.node1])
 
-    def test010_add_node_head(self):
-        # Test the addNode() method when no head exists.
+    def test010_add_second_node_head(self):
+        # Test the addNode() method when adding a second node and
+        # marking it as a head node.
+        self.graph1.addNode("Leonhard Euler", "Universitaet Basel", 1726, 38586, [], True)
+        self.assertEquals([38586, 18231], self.graph1.getNodeList())
+        self.assertEquals(self.graph1.heads, [self.node1, self.graph1.getNode(38586)])
+
+    def test011_add_node_head(self):
+        # Test the addNode() method when no heads exist.
         graph = GGraph.Graph()
-        self.assertEquals(graph.head, None)
+        self.assertEquals(graph.heads, None)
         graph.addNode("Leonhard Euler", "Universitaet Basel", 1726, 38586, [])
-        self.assertEquals(graph.head, graph.getNode(38586))
+        self.assertEquals(graph.heads, [graph.getNode(38586)])
 
-    def test011_add_node_already_present(self):
+    def test012_add_node_already_present(self):
         self.graph1.addNode("Leonhard Euler", "Universitaet Basel", 1726, 38586, [])
         self.assertEquals([38586, 18231], self.graph1.getNodeList())
         self.assertRaises(GGraph.DuplicateNodeError, self.graph1.addNode, "Leonhard Euler", "Universitaet Basel", 1726, 38586, [])
 
-    def test012_generate_dot_file(self):
+    def test013_generate_dot_file(self):
         # Test the generateDotFile() method.
         dotfileexpt = """digraph genealogy {
     graph [charset="utf-8"];
@@ -232,7 +240,7 @@ class TestGraphMethods(unittest.TestCase):
         dotfile = self.graph1.generateDotFile()
         self.assertEquals(dotfile, dotfileexpt)
         
-    def test013_generate_dot_file(self):
+    def test014_generate_dot_file(self):
         # Test the generateDotFile() method.
         graph = GGraph.Graph()
         graph.addNode("Carl Friedrich Gauss", "Universitaet Helmstedt", 1799, 18231, [18230])

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/geneagrapher.git



More information about the debian-science-commits mailing list