Python Forum
Help on a program to help with distributing food to the needy
Thread Rating:
  • 3 Vote(s) - 2.33 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help on a program to help with distributing food to the needy
#31
(Apr-08-2017, 01:29 PM)sparkz_alot Wrote: First, your latest revision. Somewhere along the line you lost the definition of 'timestr'.
     with open(filename + timestr + '.txt', 'a') as file_object: 
Second, before you get more invested in the program, you really, truly need to incorporate a database. Be it sqlite3, Postgre, or some other database. When it comes to data manipulation, text files are, to say the least, cumbersome and inefficient. As you have it, at the end of a year, you will have at least 365 files. To gather your data, you will need to access each one. Also, you really need to listen to the advice by ichabod801. If you are going to pitch this Scott, you have to show proof of concept...that your program can deliver what he wants. Something to remember, bosses like reports, even better, they like tables, but what really gets their attention is graphs. They really loves their graphs, especially if they are colorful. Even if you start small, as ichabod801 says, at least you can go to Scott and say "Here is what I can give you, just based on the sign-in sheets for the past month, I would be interested in what you would like to see in addition to this....by the way, I have a graph." (Scott now very happy and offers to buy you a car.) Finally, and this is just my opinion, but why the use of 'Fraction'? It really adds nothing to the overall script and just adds to the complexity.

Yes, i have already fixed that bug, just forgot to recopy the code once i had. Like i said, i can talk to scott on sunday about this. We only do our local giveaway once a month, so i have 3 weeks to come up with a database and better UI. The use of fraction is for getting the ratio of one;s to two's in fraction form, just in case i needed it for the calculation of the amount to give each person later. Scott, i dont think sees much of a problem with the current issue. He doesnt necessarily worry about exactly how it is being given out, so when the drivers and volunteers are giving it out, they all are under the delusion that that is how it has to be. Iwant to show them that there can be a system to relieve the stress and constant guessing on every aspect of the distribution. I thank you all again for your input, and for helping me on this project despite my lack of experience.

(Apr-08-2017, 06:52 AM)wavic Wrote: Why items[item_name] = int(item_units) and not items[item_name] = value? The exception force the user to input the item_name again.
 item_name = input("Type the name of your food item here: ") while True:     try:         item_units = int(input("Type the number of units of your item, just the number, here: "))     except ValueError:         print("Incorrect entry!") 
Printing the items after each input could be annoying and if the dictionary is big, it will fly across the screen and you'll see nothing.

I had noticed this bug already, it was on my list of things to improve. I will try your solution, thanks for mentioning it. I write the list because, at most we have 20-25 items, and the user needs feedback on the info they just entered. I will design something better than that in the long run, but for now it is what it is. I am also going to write that dictionary to the text file to save the general idea of what amounts and types of items we will be working with for you all to see. Thanks for helping me on that bug, i will try it.
Reply
#32
Here is the most recent update on the code. I am planning on adding mySQL database support soon, after i get the actual division and prediction finished. I need a little bit of help on that, I am not sure exactly how to get that working. 

 
#! /usr/bin/env python3

#For use in the total() function.
from fractions import Fraction
#To use in time and date stamps in the file written by the total() function.
import time

def get_item_info(items):
    #Requests name and amount, amount in integer form.
    while True:
        item_name = input("Type the name of your food item here: ")
        item_units = input("Type the number of units of your item, just the number, here: ")
        #The next six lines makes sure that the user has entered an integer in 
        try:
            value = int(item_units)
            break
        except ValueError:
            print('The number of units you entered: ', item_units, ' is not a normal number, please try entering it again.')
            continue
    #Writes the name and amount as the key and value in our dictionary.
    items[item_name] = int(item_units)
    #This prints the current list of items to the screen.
    for item, amount in items.items():
        print(item + ' ..... ' + str(amount))


#This function defines the process of adding new food items to the items dictionary.
def food_items(items):
    #This loop defines the user adding the items.
    while True:
        get_item_info(items)
        #After running the get_item_info function, this code will determine what the user will do next.
        next_step_option = input("Type 'a' to do another item, type 'm' to go to the main menu': ")
        #This statement says that if the input is 'a', it goes back to the top of our loop and recalls get_item_info(items)
        if next_step_option == 'a':
                print('Adding another food item')
        #This line exits to the main menu by breaking the loop, finishing the function call.
        elif next_step_option == 'm':
            break
        else:
            print('......An incorrect or blank character has been entered, try the last entry again.')

#Just a repetitive line that it isn't practical to keep writing over and over.
def show_sizes(large, small):
    print ('Large families: ', large, ' small families: ', small)
  
#This function defines the first input data and how to store that data.
def one_or_two(large, small):
    # instruction for quitting
    print("Press 'm' to go back to the main menu. Your data will be saved.")
    while True:
        letter = input("Is it a large family or small? Type l for large family, s for small: ").lower()
        if letter in ('s', 'small'):
            #adding to the value of small families 
            small = small + 1
            show_sizes(large, small)
        elif letter in ('l', 'large'):
            #adding to the value of large families
            large = large + 1
            show_sizes(large, small)
        #This exits back to the main menu by breaking the loop, finishing the function call.
        elif letter in ('m', 'main'):
            break
        else:
            print('......An incorrect or blank character has been entered, try the last entry again.')
        print()
    return large, small
  
#This function gives a tally with information when called and also writes it to a file.
def total(large, small, items):
    finalTotal = large + small
    #The following four lines print out a simple block of data.
    print('\n***There is a final total of ',finalTotal, ' families***')
    show_sizes(large, small)
    if small != 0:
        print('The ratio of large families to small families is: ' ,Fraction(large, small), ' large/small')
    else:
        print('The ratio of large families to small families is: ', large, '/0 large/small')
    print('{:.1%} of the families were large.'.format(large / finalTotal))
    
def final_total(large, small, items):
    #We set local_time to equal the current time and date.
    timestr = time.strftime("%Y%m%d-%H%M")
    
    #The next six lines make a filename that is time/date stamped and adds the specified information
    filename = 'food drive log'
    with open(filename + timestr + '.txt', 'a') as file_object:
        file_object.write('***There is a final total of ' + str(finalTotal) + ' families***\n')
        if small != 0:
            file_object.write('The ratio of large families to small families is: ' + str(Fraction(large, small)) + ' large/small\n')
        else:
            file_object.write('The ratio of large families to small families is: ' + str(large) + '/0 large/small\n')
        file_object.write('{:.1%} of the families were large.\n'.format(large / finalTotal))
        file_object.write('Large families: ' + str(large) + ' Small families: ' + str(small) + '\n')
        for item, amount in items.items():
            file_object.write(item + ' ..... ' + str(amount))

#This function is the main menu and controller of the other functions we have defined.
def main():
    #Declaring the necessary variables and dictionary.
    large, small = 0, 0
    items = {}
    while True:
        #The following is our main menu that the user will see.
        userin = input("Type 'i' to enter new items, 'r' to begin registering new families, or 't' to get currnet total and stats, e is to exit: ")
        if userin == 'i':
            food_items(items)
        elif userin == 'r':
            large, small = one_or_two(large, small)
        elif userin == 't':
            total(large, small, items)
        elif userin == 'e':
            total(large, small, items)
            final_total(large, small, items)
            break
        else:
            print('An unknown option: ', userin, ' has been entered. Please try the last entry again.')

#Calling our main function to start running the primary protions of our program.
main()
I added writing the content of our items dictionary to the log .txt file. I want to fix a few minor bugs with the items adding function, when you enter a non integer character for the unit value, you have to readd your item name as well. If you enter a non recognized character while the function is active, it prompts you to add a new item rather than go back to the selection process for the next step. I want to get the estimations working based on a fixe number of people, then move on to predictions and adjustments.
Reply
#33
MySQL requires a running server. SQLite3 will be perfect for this tiny project.
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#34
Quote: I am planning on adding mySQL database support soon

You might want to consider PostgreSQL over mySQL here are some reasons why
(compiled from several publications):
  • PostgreSQL has the PostGIS extension built in. This means that you can apply any of your data directly to maps
        which may be something you will want to do later.
  • PostgreSQL added JSON, making it one of the few relational databases to also support NoSQL.
  • PostgreSQL, built standards into the platform from the start,MySQL added them as an afterthought.
  • PostgreSQL, uses row level locking, MySQL does not.
  • This is a big one: PosrgreSQL has MIT license, this allows you complete freedom to do whatever you wish with
         the software, including commercial use, and open or closed formats. With MySQL, you need to pay a fee to
         Oracle or supply source code (which may not be an issue at this point for you)
  • PostgreSQL supports C/C++, Java, .Net, Perl, Python, Ruby, Tcl, ODBC and more
  • PostgreSQL is ACID compliant from ground up and ensures that all requirements are met.
  • Hot Standby/Streaming Replication
  • Bi-Directional replication

Obviously I am biased, the most important reasons in my opinion are
row-level locking
and
the Mapping capability. With this you can create maps of distribution points, driving instructions
for drop-offs, and so much more --- All offline.
Reply
#35
Ok, thanks for the input on that, i will look into DB's more thoroughly after the program is actually doing what i need it to. I still need to figure out the implementation of the item division, and im not quite sure how to go about it.

The basic code is now on GitHub, find it here: https://github.com/dariankbrown/The-5000 Thanks again to all who have helped.

(Apr-08-2017, 06:52 AM)wavic Wrote: Why items[item_name] = int(item_units) and not items[item_name] = value?
The exception force the user to input the item_name again.
item_name = input("Type the name of your food item here: ")
while True:
    try:
        item_units = int(input("Type the number of units of your item, just the number, here: "))
    except ValueError:
        print("Incorrect entry!")
Printing the items after each input could be annoying and if the dictionary is big, it will fly across the screen and you'll see nothing.

Wavic, I tried you solution, and it does not work. It gives an error that you tried to use local variable item_units before assignment. I'm not exactly certain how to fix that issue, so if you want to try, you can update it on the GitHub repo when you have it working. It would be nice to get rid of that bug, but I have to keep working on figuring out how to do the actual calculation for how many items to give to each family. The repo is here: https://github.com/dariankbrown/The-5000
Reply
#36
I agree with wavic on sqlite3. I use either sqlite3 or PostgreSQL on all of my projects,
sqlite3 is prefect when you need to redistribute because it's all in one file.

However, (I realize your not there yet, just tuck this info away for now) should you consider
at some point in the future something more robust, then investigate PostgreSQL.

During my career, we had to keep data for (when you combined landline, cellular and fiber -- now, Century Link (then called QWest)),
we had to deal with over 100 million customers.

I was a decision maker, and I would not have considered MySQL, but most certainly would PostgreSQL.

I'm done.
Reply
#37
def get_item_info(items):
    item_name = input("Type the name of your food item here: ")

    while True:

        try:
            item_units = int(input("Type the number of units of your item, just the number, here: "))
            break
        except ValueError:
            print("Incorrect entry!")

    items[item_name] = item_units

    for item, amount in items.items():
        print(item + ' ..... ' + str(amount))
Output:
Type the name of your food item here: eggs Type the number of units of your item, just the number, here: kls Incorrect entry! Type the number of units of your item, just the number, here: w Incorrect entry! Type the number of units of your item, just the number, here: .. Incorrect entry! Type the number of units of your item, just the number, here: 240 eggs ..... 240
I don't know why you get an error but it works here. I've missed break statement in the previous code snippet

I don't know how to deal with github Cool
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#38
Ok, I will try those changes now, I forgot to set the value as equal to the input before i referenced it. I appreciate it.
Reply
#39
Latest code update: 
#! /usr/bin/env python3

# For use in the total() function.
from fractions import Fraction
# To use in time and date stamps in the file written by the total() function.
import time


def get_item_info(items):
    # Requests name and amount, amount in integer form.
    item_name = input("\nType the name of your food item here: ")

    while any([i < 'a' or i > 'z' for i in item_name.lower()]) or (len(item_name) > 20):
        item_name = input('\nOnly use alphabetical characters with a limit of 20 characters.: ')

    while True:
        try:
            item_units = int(input("Type the number of units of your item, just the number, here: "))
            break
        except ValueError:
            print("\n\t**Incorrect entry! Make sure entered just the number of units.**\n")

    items[item_name] = item_units

    for item, amount in items.items():
        print(item + ' ..... ' + str(amount))


# This function defines the process of adding new food items to the items dictionary.
def food_items(items):
    # This loop defines the user adding the items.
    while True:
        get_item_info(items)
        # After running the get_item_info function, this code will determine what the user will do next.
        next_step_option = input("\nType 'a' to do another item, type 'm' to go to the main menu': ").lower()
        # This statement says that if the input is 'a', it goes back to the top of our loop and recalls get_item_info(items)
        if next_step_option == 'a':
            print('Adding another food item...')
        # This line exits to the main menu by breaking the loop, finishing the function call.
        elif next_step_option == 'm':
            break
        else:
            print('......An incorrect or blank character has been entered, try the last entry again.')


# Just a repetitive line that it isn't practical to keep writing over and over.
def show_sizes(large, small):
    print('Large families: ', large, ' small families: ', small)


# This function defines the first input data and how to store that data.
def one_or_two(large, small):
    # instruction for quitting
    print("\nPress 'm' to go back to the main menu. Your data will be saved.")
    while True:
        letter = input("\n\t**Is it a large family or small? Type 'l' for large family,"
                       "\n\t\t 's' for small, or 'm' to go to main menu: ").lower()
        if letter in ('s', 'small'):
            # adding to the value of small families
            small = small + 1
            show_sizes(large, small)
        elif letter in ('l', 'large'):
            # adding to the value of large families
            large = large + 1
            show_sizes(large, small)
        # This exits back to the main menu by breaking the loop, finishing the function call.
        elif letter in ('m', 'main'):
            break
        else:
            print('......An incorrect or blank character has been entered, try the last entry again.')
        print()
    return large, small


# This function gives a tally with information when called and also writes it to a file.
def total(large, small, items):
    finalTotal = large + small
    # The following four lines print out a simple block of data.
    print('\n***There is a final total of ', finalTotal, ' families***')
    show_sizes(large, small)
    if small != 0:
        print('The ratio of large families to small families is: ', Fraction(large, small), ' large/small')
    else:
        print('The ratio of large families to small families is: ', large, '/0 large/small')
    print('{:.1%} of the families were large.'.format(large / finalTotal))


def final_total(large, small, items):
    # We set local_time to equal the current time and date.
    timestr = time.strftime("%Y%m%d-%H%M")

    # The next six lines make a filename that is time/date stamped and adds the specified information
    filename = 'food drive log'
    with open(filename + timestr + '.txt', 'a') as file_object:
        file_object.write('***There is a final total of ' + str(large + small) + ' families***\n')
        if small != 0:
            file_object.write(
                'The ratio of large families to small families is: ' + str(Fraction(large, small)) + ' large/small\n')
        else:
            file_object.write('The ratio of large families to small families is: ' + str(large) + '/0 large/small\n')
        file_object.write('{:.1%} of the families were large.\n'.format(large / large + small))
        file_object.write('Large families: ' + str(large) + ' Small families: ' + str(small) + '\n')
        # This writes our dictionary to the .txt file in a loop until it is finished
        for item, amount in items.items():
            file_object.write(item + ' ..... ' + str(amount))


# This function is the main menu and controller of the other functions we have defined.
def main():
    # Declaring the necessary variables and dictionary.
    large, small = 0, 0
    items = {}
    while True:
        # The following is our main menu that the user will see.
        userin = input("\nType 'i' to enter new items, 'r' to begin registering new families,"
            "\n\t or 't' to get current total and stats, e is to exit: ").lower()
        if userin == 'i':
            food_items(items)
        elif userin == 'r':
            large, small = one_or_two(large, small)
        elif userin == 't':
            try:
                total(large, small, items)
            except ZeroDivisionError:
                print('There is nothing to calculate at this moment, please register a family.')
            else:
                main()
        elif userin == 'e':
            print('Thank you have a great day.')
            break
        else:
            print('An unknown option: ', userin, ' has been entered. Please try the last entry again.')


# Calling our main function to start running the primary protions of our program.
main()
Reply
#40
Thank you  Big Grin
If it ain't broke, I just haven't gotten to it yet.
OS: Windows 10, openSuse 42.3, freeBSD 11, Raspian "Stretch"
Python 3.6.5, IDE: PyCharm 2018 Community Edition
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Optimization problem ( food menu ) Truman 3 3,567 Apr-01-2019, 09:28 PM
Last Post: Truman
  Packaging and Distributing App for Python 3.6 solaikannan 1 2,658 Aug-21-2017, 09:36 AM
Last Post: snippsat

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020