Mad Libs Excercise











up vote
2
down vote

favorite












I did the following Excercise from Automate the boring stuff with Python Chapter 8:




Create a Mad Libs program that reads in text files and lets the user
add their own text anywhere the word ADJECTIVE, NOUN, ADVERB, or VERB
appears in the text file. For example, a text file may look like this:



The ADJECTIVE panda walked to the NOUN and then VERB. A nearby NOUN
was unaffected by these events. The program would find these
occurrences and prompt the user to replace them.



Enter an adjective:
silly

Enter a noun:
chandelier
Enter a verb:

screamed
Enter a noun:
pickup truck

The following text file would then
be created:



The silly panda walked to the chandelier and then screamed. A nearby
pickup truck was unaffected by these events. The results should be
printed to the screen and saved to a new text file.




I decided to read from all the text files which are in the same folder as the python script.
All new created files then end with _mad.txt



I would like to know if this is a good solution.



Are there any bad practices?
Is the code easy to understand?
What can be improved?
Are there better approaches for some parts int the code?



Please feel free to comment on anything you can find.



Heres the code:



mad_libs.py



"""
Mad Libs
Scans for all .txt files in the working folder.
If a file is found the file is scanned for the keywords
-ADJECTIVE
-NOUN
-ADVERB
-VERB
Then the user is prompted to add a replacing word for the keyword.
A File with the name <source_name>_mad.txt is created in the folder.
In this file the keywords are replaced with the user input
"""
import os
import sys
import re

def filenames_in_script_folder():
"""
Returns all the filenames which are located in the same folder
as this running python script
"""
os.chdir(os.path.dirname(sys.argv[0]))
return os.listdir(os.getcwd())


def words_from_file(filename):
"""
Reads text file and returns all the words in it
"""
file = open(filename)
file_content = file.read()
file.close()
return file_content.split()


def ask_for_replace_word(keyword):
"""
Asks for a replace for mentioned keyword.
Checks if keyword is a vowel to follow english grammar correct
"""
vowel_regex = re.compile('^[aeiou]')
if vowel_regex.search(keyword):
return input("Enter an " + keyword.lower() + "n")
return input("Enter a " + keyword.lower() + "n")


def replace_word(word, keywords):
"""
Replaces provided word if it matches with one of the keywords.
Any non alphabetical signs are ignored in keyword compare
Otherwise returns provided word
"""
no_char_regex = re.compile('[^a-zA-Z]')
clean_word = no_char_regex.sub('', word)

for keyword in keywords:
if clean_word == keyword:
new_word = ask_for_replace_word(keyword)
return word.replace(keyword, new_word)
return word


def write_data_to_file(data, filename):
"""
Writes provided data to file.
If no file exists a new one is created first
"""
file = open(filename, 'w')
file.write(data)
file.close()


def mad_libs():
"""
Main function reads from file, replaces keywords
and writes to new file
"""
for filename in filenames_in_script_folder():
if filename.lower().endswith('.txt'):
new_words =
replaced_a_word = False

for word in words_from_file(filename):
KEYWORDS = ('ADJECTIVE', 'NOUN', 'VERB', 'ADVERB')
replace = replace_word(word, KEYWORDS)
if replace != word:
replaced_a_word = True
new_words.append(replace)

if replaced_a_word:
new_data = ' '.join(new_words)
print(new_data)
write_data_to_file(new_data, filename[:-4] + "_mad.txt")

mad_libs()


Bonus question:

I run Pylint over the code and in the definition of the Keywords in the mad_libs function it gives me:




Severity Code Description Project File Line Suppression State
Message Variable name "KEYWORDS" doesn't conform to snake_case naming
style




Shouldnt this be ALLCAPS like i did because these words are supposed to be constants?



edit:
To see some results when run the programm you need to add a txt file like the example one in the same folder as the script.



I added a panda.txt with the text mentioned aboth and after aks for the words a panda_mad.txt is created in the folder.










share|improve this question




















  • 2




    "Shouldnt this be ALLCAPS like i did because these words are supposed to be constants?" Not true. You re-assign the values in a for loop. Should you take out the assignment to the top level, outside of any loops or function calls, yes, then it would be a pseudo-const.
    – Mast
    2 days ago















up vote
2
down vote

favorite












I did the following Excercise from Automate the boring stuff with Python Chapter 8:




Create a Mad Libs program that reads in text files and lets the user
add their own text anywhere the word ADJECTIVE, NOUN, ADVERB, or VERB
appears in the text file. For example, a text file may look like this:



The ADJECTIVE panda walked to the NOUN and then VERB. A nearby NOUN
was unaffected by these events. The program would find these
occurrences and prompt the user to replace them.



Enter an adjective:
silly

Enter a noun:
chandelier
Enter a verb:

screamed
Enter a noun:
pickup truck

The following text file would then
be created:



The silly panda walked to the chandelier and then screamed. A nearby
pickup truck was unaffected by these events. The results should be
printed to the screen and saved to a new text file.




I decided to read from all the text files which are in the same folder as the python script.
All new created files then end with _mad.txt



I would like to know if this is a good solution.



Are there any bad practices?
Is the code easy to understand?
What can be improved?
Are there better approaches for some parts int the code?



Please feel free to comment on anything you can find.



Heres the code:



mad_libs.py



"""
Mad Libs
Scans for all .txt files in the working folder.
If a file is found the file is scanned for the keywords
-ADJECTIVE
-NOUN
-ADVERB
-VERB
Then the user is prompted to add a replacing word for the keyword.
A File with the name <source_name>_mad.txt is created in the folder.
In this file the keywords are replaced with the user input
"""
import os
import sys
import re

def filenames_in_script_folder():
"""
Returns all the filenames which are located in the same folder
as this running python script
"""
os.chdir(os.path.dirname(sys.argv[0]))
return os.listdir(os.getcwd())


def words_from_file(filename):
"""
Reads text file and returns all the words in it
"""
file = open(filename)
file_content = file.read()
file.close()
return file_content.split()


def ask_for_replace_word(keyword):
"""
Asks for a replace for mentioned keyword.
Checks if keyword is a vowel to follow english grammar correct
"""
vowel_regex = re.compile('^[aeiou]')
if vowel_regex.search(keyword):
return input("Enter an " + keyword.lower() + "n")
return input("Enter a " + keyword.lower() + "n")


def replace_word(word, keywords):
"""
Replaces provided word if it matches with one of the keywords.
Any non alphabetical signs are ignored in keyword compare
Otherwise returns provided word
"""
no_char_regex = re.compile('[^a-zA-Z]')
clean_word = no_char_regex.sub('', word)

for keyword in keywords:
if clean_word == keyword:
new_word = ask_for_replace_word(keyword)
return word.replace(keyword, new_word)
return word


def write_data_to_file(data, filename):
"""
Writes provided data to file.
If no file exists a new one is created first
"""
file = open(filename, 'w')
file.write(data)
file.close()


def mad_libs():
"""
Main function reads from file, replaces keywords
and writes to new file
"""
for filename in filenames_in_script_folder():
if filename.lower().endswith('.txt'):
new_words =
replaced_a_word = False

for word in words_from_file(filename):
KEYWORDS = ('ADJECTIVE', 'NOUN', 'VERB', 'ADVERB')
replace = replace_word(word, KEYWORDS)
if replace != word:
replaced_a_word = True
new_words.append(replace)

if replaced_a_word:
new_data = ' '.join(new_words)
print(new_data)
write_data_to_file(new_data, filename[:-4] + "_mad.txt")

mad_libs()


Bonus question:

I run Pylint over the code and in the definition of the Keywords in the mad_libs function it gives me:




Severity Code Description Project File Line Suppression State
Message Variable name "KEYWORDS" doesn't conform to snake_case naming
style




Shouldnt this be ALLCAPS like i did because these words are supposed to be constants?



edit:
To see some results when run the programm you need to add a txt file like the example one in the same folder as the script.



I added a panda.txt with the text mentioned aboth and after aks for the words a panda_mad.txt is created in the folder.










share|improve this question




















  • 2




    "Shouldnt this be ALLCAPS like i did because these words are supposed to be constants?" Not true. You re-assign the values in a for loop. Should you take out the assignment to the top level, outside of any loops or function calls, yes, then it would be a pseudo-const.
    – Mast
    2 days ago













up vote
2
down vote

favorite









up vote
2
down vote

favorite











I did the following Excercise from Automate the boring stuff with Python Chapter 8:




Create a Mad Libs program that reads in text files and lets the user
add their own text anywhere the word ADJECTIVE, NOUN, ADVERB, or VERB
appears in the text file. For example, a text file may look like this:



The ADJECTIVE panda walked to the NOUN and then VERB. A nearby NOUN
was unaffected by these events. The program would find these
occurrences and prompt the user to replace them.



Enter an adjective:
silly

Enter a noun:
chandelier
Enter a verb:

screamed
Enter a noun:
pickup truck

The following text file would then
be created:



The silly panda walked to the chandelier and then screamed. A nearby
pickup truck was unaffected by these events. The results should be
printed to the screen and saved to a new text file.




I decided to read from all the text files which are in the same folder as the python script.
All new created files then end with _mad.txt



I would like to know if this is a good solution.



Are there any bad practices?
Is the code easy to understand?
What can be improved?
Are there better approaches for some parts int the code?



Please feel free to comment on anything you can find.



Heres the code:



mad_libs.py



"""
Mad Libs
Scans for all .txt files in the working folder.
If a file is found the file is scanned for the keywords
-ADJECTIVE
-NOUN
-ADVERB
-VERB
Then the user is prompted to add a replacing word for the keyword.
A File with the name <source_name>_mad.txt is created in the folder.
In this file the keywords are replaced with the user input
"""
import os
import sys
import re

def filenames_in_script_folder():
"""
Returns all the filenames which are located in the same folder
as this running python script
"""
os.chdir(os.path.dirname(sys.argv[0]))
return os.listdir(os.getcwd())


def words_from_file(filename):
"""
Reads text file and returns all the words in it
"""
file = open(filename)
file_content = file.read()
file.close()
return file_content.split()


def ask_for_replace_word(keyword):
"""
Asks for a replace for mentioned keyword.
Checks if keyword is a vowel to follow english grammar correct
"""
vowel_regex = re.compile('^[aeiou]')
if vowel_regex.search(keyword):
return input("Enter an " + keyword.lower() + "n")
return input("Enter a " + keyword.lower() + "n")


def replace_word(word, keywords):
"""
Replaces provided word if it matches with one of the keywords.
Any non alphabetical signs are ignored in keyword compare
Otherwise returns provided word
"""
no_char_regex = re.compile('[^a-zA-Z]')
clean_word = no_char_regex.sub('', word)

for keyword in keywords:
if clean_word == keyword:
new_word = ask_for_replace_word(keyword)
return word.replace(keyword, new_word)
return word


def write_data_to_file(data, filename):
"""
Writes provided data to file.
If no file exists a new one is created first
"""
file = open(filename, 'w')
file.write(data)
file.close()


def mad_libs():
"""
Main function reads from file, replaces keywords
and writes to new file
"""
for filename in filenames_in_script_folder():
if filename.lower().endswith('.txt'):
new_words =
replaced_a_word = False

for word in words_from_file(filename):
KEYWORDS = ('ADJECTIVE', 'NOUN', 'VERB', 'ADVERB')
replace = replace_word(word, KEYWORDS)
if replace != word:
replaced_a_word = True
new_words.append(replace)

if replaced_a_word:
new_data = ' '.join(new_words)
print(new_data)
write_data_to_file(new_data, filename[:-4] + "_mad.txt")

mad_libs()


Bonus question:

I run Pylint over the code and in the definition of the Keywords in the mad_libs function it gives me:




Severity Code Description Project File Line Suppression State
Message Variable name "KEYWORDS" doesn't conform to snake_case naming
style




Shouldnt this be ALLCAPS like i did because these words are supposed to be constants?



edit:
To see some results when run the programm you need to add a txt file like the example one in the same folder as the script.



I added a panda.txt with the text mentioned aboth and after aks for the words a panda_mad.txt is created in the folder.










share|improve this question















I did the following Excercise from Automate the boring stuff with Python Chapter 8:




Create a Mad Libs program that reads in text files and lets the user
add their own text anywhere the word ADJECTIVE, NOUN, ADVERB, or VERB
appears in the text file. For example, a text file may look like this:



The ADJECTIVE panda walked to the NOUN and then VERB. A nearby NOUN
was unaffected by these events. The program would find these
occurrences and prompt the user to replace them.



Enter an adjective:
silly

Enter a noun:
chandelier
Enter a verb:

screamed
Enter a noun:
pickup truck

The following text file would then
be created:



The silly panda walked to the chandelier and then screamed. A nearby
pickup truck was unaffected by these events. The results should be
printed to the screen and saved to a new text file.




I decided to read from all the text files which are in the same folder as the python script.
All new created files then end with _mad.txt



I would like to know if this is a good solution.



Are there any bad practices?
Is the code easy to understand?
What can be improved?
Are there better approaches for some parts int the code?



Please feel free to comment on anything you can find.



Heres the code:



mad_libs.py



"""
Mad Libs
Scans for all .txt files in the working folder.
If a file is found the file is scanned for the keywords
-ADJECTIVE
-NOUN
-ADVERB
-VERB
Then the user is prompted to add a replacing word for the keyword.
A File with the name <source_name>_mad.txt is created in the folder.
In this file the keywords are replaced with the user input
"""
import os
import sys
import re

def filenames_in_script_folder():
"""
Returns all the filenames which are located in the same folder
as this running python script
"""
os.chdir(os.path.dirname(sys.argv[0]))
return os.listdir(os.getcwd())


def words_from_file(filename):
"""
Reads text file and returns all the words in it
"""
file = open(filename)
file_content = file.read()
file.close()
return file_content.split()


def ask_for_replace_word(keyword):
"""
Asks for a replace for mentioned keyword.
Checks if keyword is a vowel to follow english grammar correct
"""
vowel_regex = re.compile('^[aeiou]')
if vowel_regex.search(keyword):
return input("Enter an " + keyword.lower() + "n")
return input("Enter a " + keyword.lower() + "n")


def replace_word(word, keywords):
"""
Replaces provided word if it matches with one of the keywords.
Any non alphabetical signs are ignored in keyword compare
Otherwise returns provided word
"""
no_char_regex = re.compile('[^a-zA-Z]')
clean_word = no_char_regex.sub('', word)

for keyword in keywords:
if clean_word == keyword:
new_word = ask_for_replace_word(keyword)
return word.replace(keyword, new_word)
return word


def write_data_to_file(data, filename):
"""
Writes provided data to file.
If no file exists a new one is created first
"""
file = open(filename, 'w')
file.write(data)
file.close()


def mad_libs():
"""
Main function reads from file, replaces keywords
and writes to new file
"""
for filename in filenames_in_script_folder():
if filename.lower().endswith('.txt'):
new_words =
replaced_a_word = False

for word in words_from_file(filename):
KEYWORDS = ('ADJECTIVE', 'NOUN', 'VERB', 'ADVERB')
replace = replace_word(word, KEYWORDS)
if replace != word:
replaced_a_word = True
new_words.append(replace)

if replaced_a_word:
new_data = ' '.join(new_words)
print(new_data)
write_data_to_file(new_data, filename[:-4] + "_mad.txt")

mad_libs()


Bonus question:

I run Pylint over the code and in the definition of the Keywords in the mad_libs function it gives me:




Severity Code Description Project File Line Suppression State
Message Variable name "KEYWORDS" doesn't conform to snake_case naming
style




Shouldnt this be ALLCAPS like i did because these words are supposed to be constants?



edit:
To see some results when run the programm you need to add a txt file like the example one in the same folder as the script.



I added a panda.txt with the text mentioned aboth and after aks for the words a panda_mad.txt is created in the folder.







python beginner strings file






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited yesterday

























asked 2 days ago









Sandro4912

711121




711121








  • 2




    "Shouldnt this be ALLCAPS like i did because these words are supposed to be constants?" Not true. You re-assign the values in a for loop. Should you take out the assignment to the top level, outside of any loops or function calls, yes, then it would be a pseudo-const.
    – Mast
    2 days ago














  • 2




    "Shouldnt this be ALLCAPS like i did because these words are supposed to be constants?" Not true. You re-assign the values in a for loop. Should you take out the assignment to the top level, outside of any loops or function calls, yes, then it would be a pseudo-const.
    – Mast
    2 days ago








2




2




"Shouldnt this be ALLCAPS like i did because these words are supposed to be constants?" Not true. You re-assign the values in a for loop. Should you take out the assignment to the top level, outside of any loops or function calls, yes, then it would be a pseudo-const.
– Mast
2 days ago




"Shouldnt this be ALLCAPS like i did because these words are supposed to be constants?" Not true. You re-assign the values in a for loop. Should you take out the assignment to the top level, outside of any loops or function calls, yes, then it would be a pseudo-const.
– Mast
2 days ago










1 Answer
1






active

oldest

votes

















up vote
1
down vote













Thanks for sharing your code!



Almost everything looks good to me.




  • You have documentation for the module :)

  • You have documentations for all your functions.

  • Naming seems good to me.

  • I did not see 'unpythonic' things in your code, maybe someone more experimented will have more to say on this?

  • You use a linter


The major things I would change is adding a __main__ to your script.



if __name__ == "__main__":
mad_libs()


When you run you script with python mad_libs.py it will behave the same but if you import your module in another script, it will not execute the function upon importing, which is I think the desired behavior.



As for improvements:




  • you could use type annotations to do static validation with MyPy

  • write some tests with unittest, pytest, nose ...


Very nice code in my opinion






share|improve this answer





















    Your Answer





    StackExchange.ifUsing("editor", function () {
    return StackExchange.using("mathjaxEditing", function () {
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    });
    });
    }, "mathjax-editing");

    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "196"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208713%2fmad-libs-excercise%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    1
    down vote













    Thanks for sharing your code!



    Almost everything looks good to me.




    • You have documentation for the module :)

    • You have documentations for all your functions.

    • Naming seems good to me.

    • I did not see 'unpythonic' things in your code, maybe someone more experimented will have more to say on this?

    • You use a linter


    The major things I would change is adding a __main__ to your script.



    if __name__ == "__main__":
    mad_libs()


    When you run you script with python mad_libs.py it will behave the same but if you import your module in another script, it will not execute the function upon importing, which is I think the desired behavior.



    As for improvements:




    • you could use type annotations to do static validation with MyPy

    • write some tests with unittest, pytest, nose ...


    Very nice code in my opinion






    share|improve this answer

























      up vote
      1
      down vote













      Thanks for sharing your code!



      Almost everything looks good to me.




      • You have documentation for the module :)

      • You have documentations for all your functions.

      • Naming seems good to me.

      • I did not see 'unpythonic' things in your code, maybe someone more experimented will have more to say on this?

      • You use a linter


      The major things I would change is adding a __main__ to your script.



      if __name__ == "__main__":
      mad_libs()


      When you run you script with python mad_libs.py it will behave the same but if you import your module in another script, it will not execute the function upon importing, which is I think the desired behavior.



      As for improvements:




      • you could use type annotations to do static validation with MyPy

      • write some tests with unittest, pytest, nose ...


      Very nice code in my opinion






      share|improve this answer























        up vote
        1
        down vote










        up vote
        1
        down vote









        Thanks for sharing your code!



        Almost everything looks good to me.




        • You have documentation for the module :)

        • You have documentations for all your functions.

        • Naming seems good to me.

        • I did not see 'unpythonic' things in your code, maybe someone more experimented will have more to say on this?

        • You use a linter


        The major things I would change is adding a __main__ to your script.



        if __name__ == "__main__":
        mad_libs()


        When you run you script with python mad_libs.py it will behave the same but if you import your module in another script, it will not execute the function upon importing, which is I think the desired behavior.



        As for improvements:




        • you could use type annotations to do static validation with MyPy

        • write some tests with unittest, pytest, nose ...


        Very nice code in my opinion






        share|improve this answer












        Thanks for sharing your code!



        Almost everything looks good to me.




        • You have documentation for the module :)

        • You have documentations for all your functions.

        • Naming seems good to me.

        • I did not see 'unpythonic' things in your code, maybe someone more experimented will have more to say on this?

        • You use a linter


        The major things I would change is adding a __main__ to your script.



        if __name__ == "__main__":
        mad_libs()


        When you run you script with python mad_libs.py it will behave the same but if you import your module in another script, it will not execute the function upon importing, which is I think the desired behavior.



        As for improvements:




        • you could use type annotations to do static validation with MyPy

        • write some tests with unittest, pytest, nose ...


        Very nice code in my opinion







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered yesterday









        Julien Rousé

        679517




        679517






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Code Review Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            Use MathJax to format equations. MathJax reference.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208713%2fmad-libs-excercise%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Morgemoulin

            Scott Moir

            Souastre