newmag/0000755000175000017500000000000010131455023012154 5ustar adamadam00000000000000newmag/newmag.py0000755000175000017500000007014610131455005014017 0ustar adamadam00000000000000#!/bin/env python # This is a short object orientated information retrieval system - it will # collect information about a computer magazine collection and index # the articles inside. # (c) 2004 Adam Cripps # This file is part of Newmag. # # Newmag is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # Newmag is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Newmag; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Please see the end of this file for brief developer documentation import pickle # Will be using cpickle to save all the object import sys import newmag_documentation class MagazineCollection: """This class will instantiate a new collection - this is meant to represent a topic or a subject. For my own personal use, I subscribe to 2 linux magazines and so they will fall in to this collection. The name of this object will be determined by the user from the method newcollection.""" def search(self): """This will cycle through all instances of articles to find a keyword""" my_find = -1 # Assume that nothing has been found searchfor = raw_input("What would you like to search for?") for collection_iter in self.titles: title_object = collection_iter for title_iter in title_object.issuesheld: issue_object = title_iter for issue_iter in issue_object.articlesheld: article_object = issue_iter #print article_object.name name_find = article_object.name.find(searchfor) author_find = article_object.author.find(searchfor) keywords_find = article_object.keywords.find(searchfor) if my_find <> -1 or author_find <> -1 or keywords_find <> -1: print "Search result", article_object.name #, "my_find = ", my_find print print "Magazine Title: ", title_object.name print "Issue: ", issue_object.name print "Front cover: ", issue_object.cover print print def export_to_html(self): """This method will export all the data variables to an html file """ html = raw_input("Filename (.html)?") try: htmlfile = open(html, 'w') except IOError: print "that file doesn't exist" self.export_to_html(self) #htmlfile.write('''Content-type: text/html\n\n''') htmlfile.write("""\n\n """) htmlfile.write(self.name) htmlfile.write(''' \n\n''') htmlfile.write("\n

") htmlfile.write(self.name) htmlfile.write("

") # Loop through all instance objects counter = 1 for collection_iter in self.titles: # print the headers htmlfile.write("""\n

""") htmlfile.write (collection_iter.name) htmlfile.write("""

""") title_object = collection_iter for title_iter in title_object.issuesheld: # Need some code in here to put all this info in html# htmlfile.write("""\n

""") htmlfile.write (title_iter.name) htmlfile.write ("
Cover: ") htmlfile.write (title_iter.cover) htmlfile.write("""

""") issue_object = title_iter for issue_iter in issue_object.articlesheld: # Need some code to add html info htmlfile.write("""\n

""") htmlfile.write("""(""") htmlfile.write(str(counter)) htmlfile.write(""")""") htmlfile.write("""\nTitle: """) htmlfile.write(issue_iter.name) htmlfile.write("""\n
Author: """) htmlfile.write(issue_iter.author) htmlfile.write("""\n
Keywords: """) htmlfile.write(issue_iter.keywords) htmlfile.write("""\n

""") counter = counter + 1 htmlfile.write("\n") htmlfile.write("\n") htmlfile.close() def stats(self): """This method runs statistics on the current object""" title_count = 0 issue_count = 0 article_count = 0 for collection_iter in self.titles: title_count = title_count + 1 for issue_iter in collection_iter.issuesheld: issue_count = issue_count + 1 for article_iter in issue_iter.articlesheld: article_count = article_count + 1 print "There are ", title_count, " titles\n" print "and ", issue_count, " issues\n" print "and ", article_count, " articles." return def newtitle(self): """This method is called from the Magazine Collection menu. The user specified that they want a new title and this is their chance to name one. """ newtitlename = raw_input("What is the title of the magazine?") atitle = Title(newtitlename) print "This New magazine title is ", atitle.name #atitle.savetitle() # Will save the atitle self.titles.append(atitle) # titles is a list attached to this object # which holds all the other subclasses from Title #print self.title def __init__(self, name): self.name = name self.titles = [ ] #print self.name # Just a debug to check the name is being passed correctly. #print "it did get here" def addnewissue(self): """This method will present the user with all the title objects for this collection object and ask which one they want to work with This is now defunct. """ itnum = 1 print '''Which magazine do you wish to add a new title to?''' for i in self.titles: print "Choice", itnum, "Title:", i.name itnum = itnum + 1 choice = raw_input("Please enter your choice") choice = int(choice) # Cast it to integer itnum = 1 for i in self.titles: #print "itnum is: ", itnum, "choice is: ", choice, "i is :", i.name #print "itnum is type:", type(itnum), "choice type is: ", type(choice) if choice == itnum: #Shoot off to add something to that object i.addissue() # go off to Title and add an issue else: itnum = itnum +1 print "your choice was not recognised - please try again" self.addnewissue() self.issuesmenu() def add_to_existing_issue(self): '''This will allow user to chose an issue and enter a new issue into that article. We'll loop through the objects, presenting each one as an option within a menu and then collect some input from the user which will identify that object, right down to the issue level''' count = 0 # Loop through the titles in this collection for titles_iterator in self.titles: print "(", count,") ", titles_iterator.name count = count + 1 response = raw_input("First Which one would you like to add to? ") int_response = int(response) count = 0 # Make the comparison between the response and the particular title int_break = 0 # This will flag whether we've found the one we need for titles_iterator in self.titles: if int_response == count: # We need to check for the issue print "Second Which one would you like to add to?" new_count = 0 for issue_iterator in titles_iterator.issuesheld: print "(", count,") ", issue_iterator.name issue_response = raw_input("?") int_issue_response = int(issue_response) #And now we need to loop round to compare choice with objects issue_count = 0 for issue_iterator in titles_iterator.issuesheld: if int_issue_response == issue_count: issue_iterator.addnewarticle() ######## We're gonna add an article to this issue # Somehow I need to jump out of this loop # otherwise the program continues with the second which one would you like break # My first ever use of break! else: issue_count = issue_count + 1 break # This break is vital - if we don't have it, we loop round looking for more issues else: count = count + 1 print "I didn't understand your response! Please try again" #self.add_to_existing_issue() def printdetails (self, chosen_article): print "Name :", chosen_article.name print "Author :", chosen_article.author print "Keywords: ", chosen_article.keywords return def return_object_list(self,level): list_returned=[] # print "list_returned is ", type(list_returned) """Unlike browse, this function will return a list of objects which can then be acted upon""" if level == 0: level= raw_input("""What would you like to act upon? (Title (t), Issue (i), Article (a)? You may want to choose issue if you want to delete an article from that issue. """) if level == "t" or level == "i" or level == "a": if level == "t": #object_returned = chosen_title_object for i in self.titles: # The user knows what they want - take each title and stuff it list_returned.append(i) # in to the list return (list_returned) elif level == "i" or level =="a": chosen_title_object = self.choosetitle() # We need to select a title for the object or article if level == "i": # OK they want an issue-go through that title and enter each issue in to the list for i in chosen_title_object.issuesheld: list_returned.append(i) return(list_returned) elif level== "a": chosen_article_object = self.chooseissue(chosen_title_object) for i in chosen_article_object.articlesheld: list_returned.append(i) return (list_returned) if level == "i" or level == "a": #chosen_issue_object = self.choosetitle(chosen_title_object) object_returned.append(chosen_issue_object) if level == "i": list_returned = chosen_issue_object return (list_returned) if level == "a" : chosen_article_object = self.choosearticle(chosen_issue_object) list_returned = chosen_article_object return (list_returned) else: print "I did not recognise your choice, please try again" return def browse(self,level): """This will quickly browse through the catalogue to particular parts - I don't see this as being something that will be here forever; rather this is useful to test some of the latest code""" if level == 0 : level = raw_input("""What is it you want to look for? (Title (t), Issue(i) or Article (a)) """) if level == "t" or level == "i" or level == "a": chosen_title = self.choosetitle() if level == "i" or level == "a": chosen_issue = self.chooseissue(chosen_title) if level == "a": chosen_article = self.choosearticle(chosen_issue) return (chosen_article) return (chosen_issue) return (chosen_title) def choosetitle(self): """This method allows the user to choose a title that they want to work with """ iter = 0 for i in self.titles: # This loop simply displays all the options - nothing spectial here print iter, ":", i.name iter = iter + 1 choice = raw_input("What is your choice?") intchoice = int(choice) if intchoice > iter: # Have they chosen more than the options? # print "You've chosen an incorrect choice - please try again" self.choosetitle().titlemenu else: # This little loop goes through and selects the one to run titlemenu on. iter_count = 0 for iter in self.titles: if intchoice == iter_count: print "choosetitle is saying that iter is type :", type(iter) return iter #iter.titlemenu() # Deprecated - why not just return a title, so that this can be reused for lots of things? iter_count = iter_count +1 def chooseissue(self, title): # Let's pass a title so we know which title to look through """This function will take a title and will check which issue of that title we want to use""" iter = 0 for i in title.issuesheld: # I need to change this reference to titles print iter, ":", i.name iter = iter + 1 choice = raw_input("What is title do you chose?") intchoice = int(choice) if intchoice > iter: print "You've chosen an incorrect choice - please try again" self.choose.article() # This won't work else: # This little loop goes through and selects the one to run titlemenu on. iter_count = 0 for issue_iter in title.issuesheld: # This will fail too if intchoice == iter_count: return issue_iter #return issue_iter iter_count = iter_count + 1 def choosearticle(self, issue): # An issue will be passed """This method allows the user to navigate through all the data round down to an article, which could be deleted, or whatever. It will return a list of articles in a particular issue""" new_returned_list = [] iter = 0 #print "this is articlesheld - what does the data look like?" for i in issue.articlesheld: # this should be the correct reference print iter, ":", i.name iter = iter + 1 choice = raw_input("What title do you chose?") intchoice = int(choice) if intchoice > iter: print "You've chosen an incorrect choice - please try again" self.choosearticle(issue) # By including issue here, we should restart with issue object else: # This little loop goes through and selects the one to run titlemenu on. iter_count = 0 for iter in issue.articlesheld: if intchoice == iter_count: print iter.name, " chosen." return (iter) # This iter is an article from the issue iter_count = iter_count + 1 # This next method will allow the user to choose what they want to edit, and # uses a similar algorithm as the browse, but returns a list def return_a_list(self, level): """this is an attempt to try an dresolve the deleting issues""" if level == 0: level = raw_input("What would you like to search for? a - article / i - issue / t - title ") else: if level == "t" or level == "i" or level == "a": # Only doing a at the moment print " I got this far" chosen_title_object = self.choosetitle() chosen_issue_object = self.chooseissue(chosen_title_object) chosen_article_object = self.choosearticle(chosen_issue_object) returned_list = [chosen_issue_object.articlesheld, chosen_article_object] #print returned_list return [returned_list] def choose_what_to_edit(self): # New attempt to try this one now level = 0 print " I got to choose_what_to_edit" returned_list = self.return_a_list("a") print returned_list raw_input("OK?") confirm = raw_input("Do you wish to delete this article? (y/n)") if confirm == "y": print "will be deleted" for list, object in returned_list: list.remove(object) else: print " will not be deleted " def newdelete(list_to_delete): """This function will have another stab at deleting an item, by fetching the list information of where the object is actually held - here goes!""" for val, lst in list_to_delete: lst.remove(val) return (list_to_delete) def collectionmenu(self): """The user has chosen to create a new collection. This is their initial choice set. """ print ''' ################################################# # Collection Menu # ################################################# What would you like to do? (a) Add a new magazine (b) Browse and edit (c) Add an issue to a title (ac) Add an article to an already entered issue (d) Delete an article (s) Run stats on the collection (l) Leave this collection and go back to main menu ''' response = raw_input() if response == "a": self.newtitle() self.collectionmenu() # Return back to this menu elif response =="b": self.choose_what_to_edit() elif response == "c": self.choosetitle().titlemenu() elif response =="ac": self.add_to_existing_issue() elif response =="d": print "instance of self is ", self # Debug self.deletearticle() # OK - this is it - we're going to delete stuff! self.collectionmenu() # Return back to this menu elif response == "s": self.stats() elif response == "l": confirm = raw_input("Really leave? (y/n)") # Confirm of quit if confirm == "y": #self.savecollection()# - don't save it here - it could be an issue # Need to call the save from the level above return() ##### This is causing a problem when adding a new article after already adding one elif confirm == "n": self.collectionmenu() # Loop back to the mainmenu else: print ("I didn't recognise your response") self.collectionmenu() def changename(): """This will allow you to change the name of any particular object. """ newname = raw_input("What would you like the issue to be called?") self.name = newname # This is the last line of the Class MagazineCollection class Title: """This class is a subclass of Magazine Collection and holds the title of a magazine - in my example, Linux Format. Any instances of this class takes it's name from the newtitle method. """ def __init__(self, titlename): self.name = titlename self.issuesheld = [ ] # Will hold the issue objects - there's inconsistency here - later I refer to issuesheld (s) def viewissue(self): iter = 1 for i in self.issuesheld: print iter, "Issue: ", i.name self.titlemenu() def titlemenu(self): print """ ######################################### # Title Menu # ######################################### What would you like to do? (a) Add an issue to this title (v) View issues that this title has (d) Delete issues that this title has (not yet implemented) """ response = raw_input() if response == "a": self.addissue() elif response == "v": self.viewissue() #elif response == "d": # Must go on the TODO list # self.deleteissue() else: print "I'm sorry, I didn't understand your response - please try again" self.titlemenu() def savetitle(self): """This function will save the collection as a set of objects""" file = raw_input("What is the filename?") myfile = open(file, 'w') pickle.dump(self, myfile) # This self seems to refer to an Issue # this is abug - it should be a collection print "finished" def addissue(self): """This will add an issue to the Title object """ # They've selected this from the MagazineCollection class and have # selected a title object print "you chose ", self.name issuename = raw_input("What is the date of the issue?") issuecover = raw_input("What is on the cover?") issueinstance = Issue(issuename, issuecover) self.issuesheld.append(issueinstance) # self.collectionmenu() # OK - this will have to create a list for each of the Titles and # add Issue objects into that list - issues will eventually # hold articles class Issue: """This class will create the instance of each issue - issues will hold articles which will contain the data. """ def __init__(self,issuename, issuecover): self.name = issuename self.articlesheld = [ ] # Will hold all the articles for this issue self.cover = issuecover # What appears on the cover - this is handy for # finding issues #print "On this cover you will find..>", self.cover self.issuemenu() # The user has created a new issue (from Title) #- now time to take them to the issue menu def issuechangename(): print "The issue is currently entitled:", self.name self.changename() def addnewarticle(self): newarticle = raw_input("What is the title of the article?") aninstance = Article(newarticle) self.articlesheld.append(aninstance) self.issuemenu() def viewarticles(self): for i in self.articlesheld: print i.name self.issuemenu() def issuemenu(self): print """ ################################# # Issues Menu # ################################# What would you like to do? (a) add article (v) view articles (d) delete an article (g) Go back to Magazine menu """ # (d) delete article - not yet implemented - although it has started response = raw_input() if response == "a": self.addnewarticle() elif response == "v": self.viewarticles() elif response == "d": self.deletearticles() elif response =="g": #self.collectionmenu() # Go back to a higher level of menu # Currently throws an error due to this menu expecting a Title object # rather than an issue object. return() # Using a break here instead of the code above takes you back to entry menu else: print "I did not understand your response" self.issuemenu() class Article: """This is a subclass of Issue and creates the actual article information.""" def __init__(self, articlename): self.name = articlename articleinformation = [ ] self.collectinformation(articleinformation) def collectinformation(self, articleinformation): self.author = raw_input("What is the name of the author?") self.keywords = raw_input("Any keywords?") #articleinformation.append(author) #articleinformation.append(keywords) def savecollection(aninstance): """This will save the collection and all it's sub objects""" filename = raw_input("Filename?") file = open (filename, 'w') pickle.dump(aninstance, file) print "Finished" return() def newcollection(): """New collection was called from the first menu that the user was presented with. """ name = raw_input("What is the collection of magazines called?") aninstance = MagazineCollection(name) print "The object's name is ", aninstance.name aninstance.collectionmenu() # This calls the method for the menu for this # magazine collection object. # I've returned now - and does the user want to save? #print "Ok, I've returned and self is ", aninstance.name save(aninstance) def save(aninstance): response = raw_input("Do you want to save y/n?") if response == "n": mainmenu() elif response == "y": savecollection(aninstance) mainmenu() else: print "I didn't understand your response - please try again" save(aninstance) #def search(instance): # I'm pretty sure these are deprecated # print "you chose to search", instance.name #def edit(instance): # print "you chose to edit", instance.name def edit_or_search(aninstance): """This function determines whether the user searches or edits""" response = raw_input("""Would you like to edit or search? (e) Edit (s) Search (b) Browse the catalogue (h) Export to HTML (sa) Save data (x) Exit program """) if response == "e": aninstance.collectionmenu() save(aninstance) elif response == "s": aninstance.search() mainmenu() elif response =="b": level =0 # Set this to zero, as the level of operating hasn't yet been set. aninstance.browse(level) elif response == "h": aninstance.export_to_html() elif response =="x": sure = raw_input("Are you sure?(y/n)") if sure == "y": print "bye" sys.exit(0) elif response == "sa": save(aninstance) else: print "Your response was not recognised - please try again" edit_or_search(aninstance) def loadcollection(): """This function will load a file which is a cpickled object of a magazine collection. """ filename = raw_input("What is the filename?") try: file = open (filename, 'r') except IOError: print "That file was not found!" loadcollection() instance = pickle.load(file) #instance.collectionmenu() This used to take you to the instances menu # but now we are going to a new edit/search menu edit_or_search(instance) def load_existing_collection(file): #print type (file) #print file try: openfile = open(file, 'r') instance = pickle.load(openfile) edit_or_search(instance) except IOError: print "That file doesn't exist, please try again" loadcollection() #instance = pickle.load(openfile) #edit_or_search(instance) def mainmenu(): """This method is the main entry point method that the user will first see. It asks them whether they want to create a new collection, or load an existing one""" if len(sys.argv) >1: filepassed = str(sys.argv[1]) load_existing_collection(filepassed) else: print ''' ################################### # Main Menu # ################################### What would you like to do? (n) Create a new collection (l) Load a collection (r) Read documentation (e) Exit program ''' response = raw_input() if response == "n": newcollection() elif response == "l": loadcollection() #elif response == "s": # if aninstance: # Does a collection exist already for saving? # savecollection(aninstance) # else: # print"Sorry - you don't have anything to save" elif response =="e": confirm = raw_input("Really quit? (y/n)") # Confirm of quit if confirm == "y": return elif confirm == "n": mainmenu() # Loop back to the mainmenu else: print "I'm sorry I didn't understand your response" mainmenu() elif response =="r": newmag_documentation.start() mainmenu() else: print "I didn't recognise your response, please try again" mainmenu() mainmenu() # Kicks the whole thing off # ############################################################# # # # Documentation # # # # ############################################################# # When items in the list are resolved, they are moved to the changelog to show that # that issue has been addressed - this is kind of satisfying and is a main # motivator # Couple of outstanding issues with this program: # TODO # When browsing articles, if there are no instances of titles, issues or articles, then # an empty choice is presented, which the user will never get out of without error # Bug - when the collectionmenu is spawned more than once, leaving it proves difficult # View by particular groups (magazine, issue, titles etc.) # Create media package to avoid the large download every time. # Create a media package to avoid downloads # Create a help module which opens up a browser with html content # Have to fix deletearticles as I now have an unwanted article in the file # Bug - When adding a new magazine title, the user has to add an article # Bug arises when choosing integer for choice, if no answer is given at all # Bug -once you leave this issue, it asks you to save, but then throws back to # edit-or-save function ... the only way to exit is to export # this might not actually be a bug if I put an exit at that menu - you've # already specified what file you want to work with. # Edit data? No provision for this yet # Sorting on certain data sets? # Date validation for issue dates # Exporting to HTML jumps straight out of the program # Current Search is jumping out of program on exit # Delete articles # When asking for collection, input is on same line as query # Use cpickle instead of pickle # Add more meta-information to html export # Changelog # Now adds a number to each article when exporting to html # How about passing filename as a command line parameter to start the whole shebang? # Develop function to view everything and possibly export to HTML # Bug - when entering articles and then pressing 'g' to go back, then adding another issue # a bug is filed - AttributeError: Issue instance has no attribute 'titles' # Need to be able to add articles to already added issues # Need to break out of loop in add_to_existing_issue # Spelling on view articles on titles menu (at least I think it's titles menu) # Program now allows saving if loaded at beginning # Search now jumps back to the mainmenu # Search searches all data of an article now. # Choosing which title is now correct regardless # Bug - search doesn't seem to be working now # Navigation #|issuechangename| #|return_object_list| #|choosetitle| |chooseissue| |choosearticle| #|choose_what_to_edit| # # MagazineCollection - filename # Title - name of the magazine # Issue - date of publication # Article - title of article # # # # # newmag/newmag_documentation.py0000755000175000017500000000071210130613252016737 0ustar adamadam00000000000000#!/bin/bash/env python def start(): """Starting point for documentation""" response = raw_input ("""What would you like to read about? (a) Articles (i) Issues (t) Titles (m) Magazine Collections""") if response == "a": articles_doc() else: print "Documentation coming soon ... " return def articles_doc(): """Article documentation""" print "This will tell you about articles and what you need to know about them"""