Skip to content

Instantly share code, notes, and snippets.

@luciomartinez
Last active December 18, 2015 02:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save luciomartinez/5710766 to your computer and use it in GitHub Desktop.
Save luciomartinez/5710766 to your computer and use it in GitHub Desktop.
Persons is a CLI Unix system wrote in Python. This application offer the possibility to create, edit, save and remove information with a command line interface.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# __init__.py
#~
#~ This file is part of Persons.
#~
#~ Persons Copyright © 2013 Lucio
#~
#~ This is free software, and you are welcome to redistribute it
#~ under certain conditions;
#~ see <http://ubuntuone.com/6lIaO1Ei1AH7zAMU1bYVw5> for details.
#~ This program comes with ABSOLUTELY NO WARRANTY;
#~ for details see <http://ubuntuone.com/6lIaO1Ei1AH7zAMU1bYVw5>.
#~
#~ You should have received a copy of the GNU General Public License
#~ along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from Persons import Persons
from GetChar import GetchUnix
# Enter all the persons that the user want to
def enter_persons(persons):
# The user will add many users as he wants to
user_response = "y"
while (user_response=='y')|(user_response=='Y'):
# Clear the terminal screen
os.system('clear')
print "Registering a new person.."
name = raw_input(" Enter the name: ")
age = raw_input(" Enter the age: ")
email = raw_input(" Enter the email: ")
# Add the given values to the object node
success = persons.add(name, age, email)
if not success:
print "\nThe values entered are incorrect. This information could not be saved."
else:
print "\nThe new person was added successfully!"
user_response = raw_input("""\nIf you want to add another person enter 'Y',
otherwise enter any character else.. """)
# Clear the screen before exit from the method
os.system('clear');
# Show every person in the list
def show_persons(persons):
top = persons.amount()
if top > 0:
for i in range(top):
print "Person number %d:"%(i+1)
print(" - Name: " + persons.get_name(i))
print(" - Age: " + str(persons.get_age(i)))
print(" - E-mail: " + persons.get_email(i))
else:
print "There are no persons on the list."
def remove_person(persons):
getch = GetchUnix()
os.system('clear')
name = raw_input("Enter the name of the required person: ")
index = persons.get_persons_with_name(name)
top = len(index)
if top == 0:
print "There are no persons with the name entered."
else:
print "Persons that match the entered name: "
for i in range(top):
print "\nPerson number %d:"%(i+1)
print " - Name: " + persons.get_name(index[i])
print " - Age: " + str(persons.get_age(index[i]))
print " - E-mail: " + persons.get_email(index[i])
print "\nNow you need to enter the number of the person"
print "that you want to remove from the list."
try:
pos = int(raw_input("Person's number: "))
except ValueError:
pos = 0
if 0 < pos <= top:
email = persons.get_email(index[pos-1])
res = persons.remove_person_by_email(email)
if not res:
print "ERROR: the selected person could not be removed."
else:
print "The selected person was successfully removed!"
else:
print "ERROR: invalid index."
getch()
def save_information(persons, path):
getch = GetchUnix()
if persons.amount() > 0:
print """What do you want to do:
1 - ERASE all the actual information of the file and save there.
2 - ADD the actual information to the information of file appending.
3 - Go back to the menu and don't save anything."""
user_response = raw_input("Enter 1 or 2 or 3 to choice one option: ")
if (user_response=='1')|(user_response=='2'):
if user_response == '1':
res = persons.save_to_file(path, True)
elif user_response == '2':
res = persons.save_to_file(path)
if res:
print "All the information was saved successfully!"
else:
print "ERROR: the information could not be saved."
else:
print "Nothing has been saved.."
else:
print "There are no persons to save!"
getch()
def load_information(persons, path):
getch = GetchUnix()
print """What do you want to do:
1 - ERASE all the actual information and load the information from the file.
2 - ADD the information from the file to the actual information
3 - Go back to the menu and don't modify anything"""
user_response = raw_input("Enter 1 or 2 or 3 to choice one option: ")
if (user_response=='1')|(user_response=='2'):
if user_response == '1':
res = persons.load_from_file(path, True)
elif user_response == '2':
res = persons.load_from_file(path)
if res:
print "All the information was loaded successfully!"
else:
print "ERROR: the information could not be loaded."
else:
print "Nothing has been modified.."
getch()
def confirm_reset(persons):
'''Request a confirmation to the user,
to proceed to remove all the information.
It wont modify any local file
'''
getch = GetchUnix()
print "Are you sure that you want to remove all the persons from the actual list?"
print "NOTE: this wont modify any local file.\n"
user_response = raw_input("Enter 1 to confirm or anything else to cancel: ")
if user_response == '1':
persons.clear_all()
print "The information was removed successfully!"
else:
print "Nothing has been modified.."
getch()
def show_menu(persons, path):
# Instantiate the class so we can then call the method
getch = GetchUnix()
os.system('clear')
print """The following actions are available:
1 - Add persons to the list
2 - Show the content of the list
3 - Save the list on an external file
4 - Load the persons from an external file
5 - Remove a specific person from the list
6 - Clear all the list
10 - Exit the application
"""
user_response = raw_input("Enter the number of the desire option.. ")
os.system('clear')
if user_response == '1':
enter_persons(persons)
elif user_response == '2':
show_persons(persons)
getch()
elif user_response == '3':
save_information(persons, path)
elif user_response == '4':
load_information(persons, path)
elif user_response == '5':
remove_person(persons)
elif user_response == '6':
confirm_reset(persons)
elif user_response == '10':
return False
else:
raw_input("You need to enter a valid number!")
# If returns true, then it should be called again
return True
def main():
# This is presumming that there is a folder called 'data'
# on the parent directory, containing the file 'data.list'
# In this file will be saved and loaded the persons.
path = os.path.normpath(os.getcwd()+'/../'+'data')+'/data.list'
persons = Persons()
# When the function returns false,
# then the program will finish.
# Otherwise, it will show the menu again
while show_menu(persons, path):
pass
if __name__ == '__main__':
main()
#~ Created by Danny Yoo on Fri, 21 Jun 2002
#~ Under the PSF license
#~ http://code.activestate.com/recipes/134892/
class GetchUnix:
def __init__(self):
import tty, sys
def __call__(self):
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# __init__.py
#~
#~ This file is part of Persons.
#~
#~ Persons Copyright © 2013 Lucio
#~
#~ This is free software, and you are welcome to redistribute it
#~ under certain conditions;
#~ see <http://ubuntuone.com/6lIaO1Ei1AH7zAMU1bYVw5> for details.
#~ This program comes with ABSOLUTELY NO WARRANTY;
#~ for details see <http://ubuntuone.com/6lIaO1Ei1AH7zAMU1bYVw5>.
#~
#~ You should have received a copy of the GNU General Public License
#~ along with this program. If not, see <http://www.gnu.org/licenses/>.
# Necessary for the regular expressions
import re
class Persons:
def __init__(self):
self.persons = []
def get_name(self, index):
'''Returns a string with the name of the person
that is on the index position (starts at zero).
If the index is invalid, return an empty string ("").
'''
try:
return self.persons[index][0]
except IndexError:
return ""
def get_age(self, index):
'''Returns an integer with the age of the person
that is on the index position (starts at zero).
If you want to handle the returned value as a string,
put it inside the str() function.
If the index is invalid, return zero (0).
'''
try:
return self.persons[index][1]
except IndexError:
return 0
def get_email(self, index):
'''Returns a string with the e-mail of the person
that is on the index position (starts at zero).
If the index is invalid, return an empty string ("").
'''
try:
return self.persons[index][2]
except IndexError:
return ""
def get_position_by_email(self, email):
'''Receives a string and return the position
of the persons that have this email.
If no person have this email, then will return -1.
'''
top = self.amount()
if top > 0:
for i in range(top):
if self.get_email(i) == email:
return i
return -1
def is_email_on_list(self, email):
'''Check if the email is already on the list.
Returns false if it does not.
'''
top = self.amount()
if top > 0:
for i in range(top):
if self.get_email(i) == email:
return True
# Reached if the email is not on the list
return False
def add(self, name, age, email):
'''Add a new person to the list.
The age must be an integer value, or a string that can be converted.
The email cannot be on the list. Making this an unique field.
Returns true when success, or false if values entered are incorrect.
'''
try:
if (not self.__validate_email(email)) | (not self.__validate_name(name)) | (1<int(age)<120) | (self.is_email_on_list(email)):
return False
self.persons.append((name, int(age), email))
return True
except ValueError:
return False
def amount(self):
'''Returns an integer with the amount of persons (items)
that are on the list.
'''
return len(self.persons)
def get_persons_with_name(self, name):
'''Return a list of integers with indexs.
Each index will be the position of a person that his name
match with the given name or a part of this string.
'''
# This list will contain integers
newlist = []
top = self.amount()
if top > 0:
for i in range(top):
if self.get_name(i).find(name) == 0:
# The name (or a part of this) is on the node
# Then we add their index to the new list
newlist.append(i)
return newlist
def clear_all(self):
'''Clear the list, removing all the information there.
'''
self.persons = []
def remove_person_by_email(self, email):
'''Remove a specific person from the list.
To separate this person from every one else,
this function receive the email (an unique value).
If the person was successfully removed, then return true.
'''
position = self.get_position_by_email(email)
if position > -1:
self.persons.pop(position)
return True
return False
def save_to_file(self, path, create=False):
'''Save all the persons of the list in a CVS text file.
This function receives the path to the file,
and (optinally) a boolean:
- if false (default): append the information in the existent (or new) file.
- if true: create (and overwrite if necessary) the file.
If operation completed successfully,
then it returns true, else it returns false.
'''
try:
if not create:
f = open(path, 'a')
else:
f = open(path, 'w')
top = self.amount()
for i in range(top):
f.write(self.get_name(i) + ", " + str(self.get_age(i)) + ", " + self.get_email(i) + '\n')
f.close()
return True
except IOError:
return False
def load_from_file(self, path, create=False):
'''Read all the persons contained in a CVS text file.
This function receives the path to the file,
and (optionally) a boolean:
- if false (default): add all the persons of the file
at the end of the actual list.
- if true: all the persons in the actual list will be removed,
and it will create a new list with the persons of the file.
If operation completed successfully,
then it returns true, else it returns false.
'''
if create:
# Clear the list
self.clear_all()
try:
f = open(path, 'r')
for line in f:
first_divisor = line.index(',')
second_divisor = self.__find_nth(line,",")
# Save the three values on independent variables
name = line[0 : first_divisor]
age = line[first_divisor+2 : second_divisor]
email = line[second_divisor+2 : len(line)-1]
# Add the variable's values to the list
self.persons.append((name, age, email))
f.close()
return True
except IOError:
return False
except ValueError:
return False
#~ The following methods are internal and it should not be
#~ instantiated, called nor even mentioned from an external scope!
#~ Lets keep this as a secret :)
def __find_nth(self, str1, substr1):
'''Internal function that returns the position
of the second appearance of the substring on the string.
This method should not be called outside the class!
'''
return str1.find(substr1, str1.find(substr1)+1)
# This will only avoid a string with numbers
def __validate_name(self, name):
'''Internal function that check the entered name.
This should return True if the string entered
has a valid format, and should return false
if it contains invalid character.
This method should not be called outside the class!
'''
if re.search("\d", name) == None:
# No digit is inside the string 'name'
return True
else:
return False
def __validate_email(self, email):
'''Internal function that check the entered email.
This should return True if the string entered has a valid format.
Example of a valid format: 'X@Y.ZZZ' where X>1 & Y>1
This method should not be called outside the class!
'''
try:
atpos = email.index('@')
# Get the position of the first '.' after '@'
dotpos = email.find('.', email.find('@'))
top = len(email)
if (top<128)&(email.count('@')==1)&(atpos >= 1)&(dotpos == top-4):
return True
else:
# string 'email' has a invalid format
return False
except ValueError:
# Reached if no at character ('@') was found
return False
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment