My first “real” Python Program pt. 2


In the first post about my first real Python program, I talked about how I parsed out stories based upon a tag-based markup system, prompted the user for values for all of the tags, and then returned the story with all user input in place. Today I will be talking about how I created a system to allow users to write their own stories and have them automatically detected and parsed, as well as allowing users to save their created stories.

To start, we need to import some libraries for added functionality:

import os  # We need this to work with files and folders
import random # For choosing random files
import dircache # For listing the files in a directory
import sys # For accepting command line arguments

and then define a function we will be using later:

def safemk(path): # Allows for the creation of a directory if it does not already exist
    if os.path.exists(path): # If the directory already exists, our work here is done
        return True # So we return
    else: # Otherwise, try to create it
        try:
            os.makedirs(path)
        except IOError: # If something breaks
            return False # We return false
        return True # otherwise return true

Now for the real work. We start out by looking for command line arguments. Since a user may enter 0, 1, or 2 arguments on the command line, we need a good way to handle each possible combination. One thing to note when dealing with command line arguments in Python, there will always be at least one argument: The name of the file currently being executed by python. I can’t think of a reason we would ever need that, so we ignore it.

dir = 'C:\\Users\\brendon\\Desktop\\Python\\My Python Scripts\\madlibs\\'
        if (len(sys.argv) == 1):
            filename = random.choice(dircache.listdir(dir))
            while os.path.isdir(filename):
                filename = random.choice(dircache.listdir(dir))
        else:
            if (len(sys.argv) == 2):
                if "\\" in sys.argv[1] or "/" in sys.argv[1]:#First argument is a directory
                    dir = sys.argv[1]
                    filename = random.choice(dircache.listdir(dir))
                    while os.path.isdir(filename):
                        filename = random.choice(dircache.listdir(dir))
                else:
                    filename = sys.argv[1]
            if (len(sys.argv) == 3):
                if "\\" in sys.argv[1] or "/" in sys.argv[1]:#First argument is a directory
                    dir = sys.argv[1]
                    filename = sys.argv[2]
                else:
                    dir = sys.argv[2]
                    filename = sys.argv[1]
        path = os.path.join(dir, filename)
        f = open(path, 'r')

We start out by assigning a default value to the variable ‘dir’. This is the directory in which I currently keep all of my stories, and if there are no command line arguments ( if (len(sys.argv) == 1): ) we are going to randomly choose a file from this directory to parse.

If there is a single argument on the command line, we first check to see if it contains either a “\” character or a “/” character, which depending on OS type would be a path separator, indicating that it is a directory. If it is a directory, we choose a random file from within that directory to parse. You may have noticed above that there is a short while loop inside the random file selection process. This is to prevent trying to parse a directory instead of a file (which would crash the program). If the one command line argument is not a directory, we will assume it is a file name, and choose that file from the default directory.

If there are two arguments on the command line, we check to see if the first one is a directory like we did above. If it is, we assume that the first argument is a directory and the second is a file name and parse that file. Otherwise, we assume the first argument is the file name and the second is the path, and still parse the file. In this way, we are able to accept any of the following inputs to successfully run the program:

python madlibTester.py
python madlibTester.py test.txt
python madlibTester.py "C:\Users\brendon\Desktop\Python\My Python Scripts\test"
python madlibTester.py "C:\Users\brendon\Desktop\Python\My Python Scripts\test" test.txt
python madlibTester.py test.txt "C:\Users\brendon\Desktop\Python\My Python Scripts\test"

Now that we have given the program the ability to handle the arguments we throw at it, let’s code in the functionality for parsing the story (which is much the same as the first part of this post):

        try:
            story = f.read()
            output = madlib.parseAndCompleteStory(story)
            print output
        finally:

Since we wrote all of the functionality into a single function before, we simply pass the contents of the file to the madlib library, and VoilĂ , the rest is taken care of automatically. The only thing left to do is offer the user the opportunity to save their hilarious story for later:

            f.close()
            filename = raw_input("To save your story, type in a name for it, otherwise type quit to exit:  ")
            if filename.lower() != "quit":
                safemk(os.path.join(dir, "Saved Madlibs"))
                dir = os.path.join(dir, "Saved Madlibs")
                path = os.path.join(dir,  "%s.txt" % (filename))
                try:
                    f = open(path, 'w')
                    f.write(output)
                    print "File saved at %s Successfully!" % (path)
                except IOError as e1:
                    print "There was an error Writing to the file:"
                    print e1
                finally:
                    f.close()
            else:
                print "Exiting without saving. Goodbye!"
    except IOError as e:
        print "An Error has occurred. Check the file name and try again."
        print e

Note that we are making use of the function we created above to double check that the directory we want to save the story in exists, and creating it if it doesn’t. Below you will find the source files needed to run this yourself, as well as a few test stories. Enjoy!

madlib.py

import re
"""
    Creates a simple tag based system for creating and parsing Mad-Libs style stories.
"""
__author__ = "Brendon Dugan (wishingforayer@gmail.com)"


def buildWordList(prompt, number):
    """Allows the user to create a list of words from a custom prompt

    Returns list"""
    words = ["test"]
    try:
        for i in range(0, number):
            if i == 0:
                words.insert(0, raw_input("%s (%d of %d): " % (prompt, i+1, number)))
                words.remove("test")
            else:
                words.append(raw_input("%s (%d of %d): " % (prompt, i+1, number)))
        return words
    except KeyboardInterrupt:
        print "User Cancelled Action"

def countBlanksOfType(blankType, story):
    """Allows the user to find out how many tags of a certain type are in a story

    Returns int"""    
    tag = "[%s]" % (blankType)
    return story.count(tag)

def replaceBlanksByType(blankType, story, wordList):
    """Allows the user to replace all tags of a certain type with list items from a matching list

    Returns string"""    
    tag = "[%s]" % (blankType)
    for word in wordList:
        story = story.replace(tag, word, 1)
    return story

def createDictionaryOfTags(story):
    """Returns a dictionary containing each tag and a list in which to store all variables
    """
    tagDef = re.compile("\[\w*\]")
    tags = tagDef.findall(story)
    tagDict = {}
    for tag in tags:
        value = tag.replace('[', '')
        value = value.replace(']', '')
        if value in tagDict:
            value = value
        else:
            tagDict[value] = "placeholder"
    return tagDict

def buildPromptByTagName(tag):
    tag = tag.replace('[', '')
    tag = tag.replace(']', '')
    vowels = "aeiouAEIOU"
    if tag[0] in vowels:
        prompt = "Please enter an %s" % (tag.replace('_', ' '))
    else:
        prompt = "Please enter a %s" % (tag.replace('_', ' '))
    return prompt

def parseAndCompleteStory(story):
    """Allows a properly formatted string to be parsed, all input received from the user, and formatted into a mad-libs
    style story

    Returns string"""    
    tags = createDictionaryOfTags(story)
    for k in tags:
        tags[k] = buildWordList(buildPromptByTagName(k), countBlanksOfType("%s" % (k), story))
        try:
            story = replaceBlanksByType(k, story, tags[k])
        except:
            return "User Cancelled Action"
    return story    

if __name__ == "__main__":
    story = """
I like [adjective] [plural_noun] and I cannot [verb]
You other [plural_noun] can't [verb]
When a [noun] [verb_ending_in_s] in with an [adjective] waist
And a [adjective] thing in your [noun]
You get [past_tense_verb]
    """
    print parseAndCompleteStory(story)       

madlibTester.py

import madlib
import os
import random
import dircache
import sys

def safemk(path):
    if os.path.exists(path):
        return True
    else:
        try:
            os.makedirs(path)
        except IOError as e:
            return False
        return True

if __name__ == "__main__":
    try:
        dir = 'C:\\Users\\brendon\\Desktop\\Python\\My Python Scripts\\madlibs\\'
        if (len(sys.argv) == 1):
            filename = random.choice(dircache.listdir(dir))
            while os.path.isdir(filename):
                filename = random.choice(dircache.listdir(dir))
        else:
            if (len(sys.argv) == 2):
                if "\\" in sys.argv[1] or "/" in sys.argv[1]:#First argument is a directory
                    dir = sys.argv[1]
                    filename = random.choice(dircache.listdir(dir))
                    while os.path.isdir(filename):
                        filename = random.choice(dircache.listdir(dir))
                else:
                    filename = sys.argv[1]
            if (len(sys.argv) == 3):
                if "\\" in sys.argv[1] or "/" in sys.argv[1]:#First argument is a directory
                    dir = sys.argv[1]
                    filename = sys.argv[2]
                else:
                    dir = sys.argv[2]
                    filename = sys.argv[1]
        path = os.path.join(dir, filename)
        f = open(path, 'r')
        try:
            story = f.read()
            output = madlib.parseAndCompleteStory(story)
            print output
        finally:
            f.close()
            filename = raw_input("To save your story, type in a name for it, otherwise type quit to exit:  ")
            if filename.lower() != "quit":
                safemk(os.path.join(dir, "Saved Madlibs"))
                dir = os.path.join(dir, "Saved Madlibs")
                path = os.path.join(dir,  "%s.txt" % (filename))
                try:
                    f = open(path, 'w')
                    f.write(output)
                    print "File saved at %s Successfully!" % (path)
                except IOError as e1:
                    print "There was an error Writing to the file:"
                    print e1
                finally:
                    f.close()
            else:
                print "Exiting without saving. Goodbye!"
    except IOError as e:
        print "An Error has occurred. Check the file name and try again."
        print e

The Raven

The Raven

Once upon a midnight dreary, while I [intransitive_past_tense_verb], [adjective] and weary,
Over many a [adjective] and [adjective] volume of [adjective] lore,
While I [intransitive_past_tense_verb], nearly napping, [adverb] there came a tapping,
As of some one [adverb] rapping, rapping at my [room] door.
"'Tis some [relationship]," I muttered, "tapping at my [room] door
Only this, and nothing more."

[exclamation], [adverb] I remember it was in the [adjective] December,
And each [adjective] dying ember wrought its [noun] upon the floor.
[adverb] I wished the morrow; [adverb] I had tried to borrow
From my [plural_noun] surcease of sorrow; sorrow for the lost Lenore
For the rare and [adjective] [person] whom the [plural_person] name Lenore
Nameless here for evermore.

And the silken [adjective] uncertain [intransitive_gerund] of each [color] curtain
Thrilled me; filled me with fantastic [abstract_noun] never felt before;
So that now, to still the beating of my [internal_organ], I stood repeating
"'Tis some [relationship] entreating entrance at my [room] door
Some [adjective] [relationship] entreating entrance at my [room] door;
This it is, and nothing more."

‘Twas the Night Before Christmas

'Twas the Night Before Christmas

'Twas the [time_period] before Christmas, and all through the [dwelling],
Not a creature was stirring, not even a [animal].
The [plural_article_of_clothing] were hung by the [furniture] with care,
In hopes that St. [first_name] soon would be there.

The children were nestled all snug in their [plural_furniture],
While visions of sugar-[plural_food] danced in their [plural_body_part].
And [relationship] in her 'kerchief, and I in my cap,
Had just settled down for a long winter's nap.

When out on the lawn there arose such a clatter,
I sprang from the [furniture] to see what was the matter.
Away to the window I flew like a flash,
[transitive_past_tense_verb] open the shutters, and [transitive_past_tense_verb] up the sash.

The moon on the breast of the new-fallen snow,
Gave the luster of mid-[time_period] to objects below.
When, what to my wondering eyes should appear?
But a [adjective] [noun], and eight tiny [plural_animal].

With a little old driver, so lively and [adjective],
I knew in a moment it must be St. [first_name].
More rapid than [plural_animal] his [plural_animal] they came,
And he whistled, and [intransitive_past_tense_verb], and called them by name;
"Now, Dasher! Now, [first_name]! Now, [noun] and Vixen!
On, [person]! On [animal]! On, [article_of_clothing] and Blitzen!
To the top of the porch! To the top of the [noun]!
Now [intransitive_present_tense_verb] away! [intransitive_present_tense_verb] away! [intransitive_present_tense_verb] away all!"

And then, in a twinkling, I heard on the roof,
The prancing and pawing of each little hoof.
As I drew in my hand, and was turning around,
Down the [furniture] St. [first_name] came with a bound.

His eyes -- how they [intransitive_past_tense_verb]! His dimples, how [adjective]!
His [plural_body_part] were like [plural_noun], his [body_part] like a [singular_food]!

He spoke not a word but went straight to his work,
And filled all the [plural_article_of_clothing], then turned with a jerk.
And laying his [body_part] aside of his [body_part],
And giving a nod, up the [furniture] he rose.

He sprang to his sleigh, to his team gave a [sound],
And away they all flew like the down of a thistle.
But I heard him exclaim, as he drove out of sight,
"Merry Christmas to all, and to all a good [time_period]!"

Great Expectations

Great Expectations
"What's in the [container], [person]?" said he.

"[liquid]," said I.

He was already handing [plural_food] down his [body_part] in the most [adjective] manner,--more like a [person] who was putting it away somewhere in a [adjective] hurry, than a [person] who was [transitive_gerund] it,--but he left off to [present_tense_transitive_verb] some of the [liquid]. He [present_tense_intransitive_verb] all the while so [adverb], that it was quite as much as he could do to keep the neck of the [container] between his [plural_body_part], without [transitive_gerund] it off.

"I think you have got [disease]," said I.

"I'm much of your opinion, [person]," said he.

"It's bad about here," I told him. "You've been [intransitive_gerund] out on the [geographical_terrain], and they're dreadful aguish. Rheumatic too."

"I'll eat my [plural_food] afore they're the death of me," said he. "I'd do that, if I was going to be [past_tense_transitive_verb] up to that there gallows as there is over there, directly afterwards. I'll beat the [abstract_noun] so far, I'll bet you."

He was [transitive_gerund] [plural_food], [plural_food], [plural_food], [plural_food], and [plural_food], all at once: staring [adverb] while he did so at the [noun] all round us, and often [intransitive_gerund]--even [transitive_gerund] his [plural_body_part]--to [present_tense_intransitive_verb].
Advertisements
Previous Post
Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s