-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d21f5e3
commit 7bdca94
Showing
21 changed files
with
2,700 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# This file lists all individuals having contributed content to the repository. | ||
Edwin waweru |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
.... | ||
..... | ||
Description 🏠 | ||
Airbnb clone is a complete web application, integrating database storage, a back-end API, and front-end interfacing in a clone of AirBnB. | ||
|
||
The project currently only implements the back-end console. | ||
|
||
Classes 🆑 | ||
AirBnB utilizes the following classes: | ||
|
||
BaseModel FileStorage User State City Amenity Place Review | ||
PUBLIC INSTANCE ATTRIBUTES id | ||
created_at | ||
updated_at Inherits from BaseModel Inherits from BaseModel Inherits from BaseModel Inherits from BaseModel Inherits from BaseModel Inherits from BaseModel | ||
PUBLIC INSTANCE METHODS save | ||
to_dict all | ||
new | ||
save | ||
reload "" "" "" "" "" "" | ||
PUBLIC CLASS ATTRIBUTES email | ||
password | ||
first_name | ||
last_name name state_id | ||
name name city_id | ||
user_id | ||
name | ||
description | ||
number_rooms | ||
number_bathrooms | ||
max_guest | ||
price_by_night | ||
latitude | ||
longitude | ||
amenity_ids place_id | ||
user_id | ||
text | ||
PRIVATE CLASS ATTRIBUTES file_path | ||
objects | ||
Storage 🛄 | ||
The above classes are handled by the abstracted storage engine defined in the FileStorage class. | ||
|
||
Every time the backend is initialized, AirBnB instantiates an instance of FileStorage called storage. The storage object is loaded/re-loaded from any class instances stored in the JSON file file.json. As class instances are created, updated, or deleted, the storage object is used to register corresponding changes in the file.json. | ||
|
||
Console 💻 | ||
The console is a command line interpreter that permits management of the backend of AirBnB. It can be used to handle and manipulate all classes utilized by the application (achieved by calls on the storage object defined above). | ||
|
||
Using the Console | ||
The AirBnB console can be run both interactively and non-interactively. To run the console in non-interactive mode, pipe any command(s) into an execution of the file console.py at the command line. | ||
|
||
$ echo "help" | ./console.py | ||
(hbnb) | ||
Documented commands (type help <topic>): | ||
======================================== | ||
EOF all count create destroy help quit show update | ||
|
||
(hbnb) | ||
$ | ||
Alternatively, to use the AirBnB console in interactive mode, run the file console.py by itself: | ||
|
||
$ ./console.py | ||
While running in interactive mode, the console displays a prompt for input: | ||
|
||
$ ./console.py | ||
(hbnb) | ||
To quit the console, enter the command quit, or input an EOF signal (ctrl-D). | ||
|
||
$ ./console.py | ||
(hbnb) quit | ||
$ | ||
$ ./console.py | ||
(hbnb) EOF | ||
$ | ||
Console Commands | ||
The AirBnB console supports the following commands: | ||
|
||
create | ||
Usage: create <class> | ||
Creates a new instance of a given class. The class' ID is printed and the instance is saved to the file file.json. | ||
|
||
show | ||
Usage: show <class> <id> or <class>.show(<id>) | ||
Prints the string representation of a class instance based on a given id. | ||
|
||
$ ./console.py | ||
(hbnb) create User | ||
(hbnb) | ||
(hbnb) show User uid | ||
(hbnb) | ||
(hbnb) User.show(uid) | ||
(hbnb) | ||
destroy | ||
Usage: destroy <class> <id> or <class>.destroy(<id>) | ||
Deletes a class instance based on a given id. The storage file file.json is updated accordingly. | ||
|
||
$ ./console.py | ||
(hbnb) create State | ||
(hbnb) create Place | ||
(hbnb) | ||
(hbnb) destroy State uid | ||
(hbnb) Place.destroy(uid) | ||
(hbnb) quit | ||
$ cat file.json ; echo "" | ||
{} | ||
all | ||
Usage: all or all <class> or <class>.all() | ||
Prints the string representations of all instances of a given class. If no class name is provided, the command prints all instances of every class. | ||
|
||
$ ./console.py | ||
(hbnb) create BaseModel | ||
(hbnb) create BaseModel | ||
(hbnb) create User | ||
(hbnb) create User | ||
(hbnb) | ||
(hbnb) all BaseModel | ||
(hbnb) | ||
(hbnb) User.all() | ||
(hbnb) | ||
(hbnb) all | ||
count | ||
Usage: count <class> or <class>.count() | ||
Retrieves the number of instances of a given class. | ||
|
||
$ ./console.py | ||
(hbnb) create Place | ||
(hbnb) create Place | ||
(hbnb) create City | ||
(hbnb) | ||
(hbnb) count Place | ||
2 | ||
(hbnb) city.count() | ||
1 | ||
(hbnb) | ||
update | ||
Usage: update <class> <id> <attribute name> "<attribute value>" or <class>.update(<id>, <attribute name>, <attribute value>) or <class>.update( <id>, <attribute dictionary>). | ||
Updates a class instance based on a given id with a given key/value attribute pair or dictionary of attribute pairs. If update is called with a single key/value attribute pair, only "simple" attributes can be updated (ie. not id, created_at, and updated_at). However, any attribute can be updated by providing a dictionary. | ||
|
||
$ ./console.py | ||
(hbnb) create User | ||
(hbnb) | ||
(hbnb) update User id first_name "name" | ||
(hbnb) show User uid | ||
(hbnb) | ||
(hbnb) User.update(uid), address, "address") | ||
(hbnb) User.show(uid) | ||
(hbnb) | ||
(hbnb) User.update(uid, {'email': 'email', 'last_name': 'last_name'}) | ||
(hbnb) | ||
Testing 📏 | ||
Unittests for the Airbnb_clone project are defined in the tests folder. To run the entire test suite simultaneously, execute the following command: | ||
|
||
$ python3 unittest -m discover tests | ||
Alternatively, you can specify a single test file to run at a time: | ||
|
||
$ python3 unittest -m tests/test_console.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
#!/usr/bin/python3 | ||
"""Defines the HBnB console.""" | ||
import cmd | ||
import re | ||
from shlex import split | ||
from models import storage | ||
from models.base_model import BaseModel | ||
from models.user import User | ||
from models.state import State | ||
from models.city import City | ||
from models.place import Place | ||
from models.amenity import Amenity | ||
from models.review import Review | ||
|
||
|
||
def parse(arg): | ||
curly_braces = re.search(r"\{(.*?)\}", arg) | ||
brackets = re.search(r"\[(.*?)\]", arg) | ||
if curly_braces is None: | ||
if brackets is None: | ||
return [i.strip(",") for i in split(arg)] | ||
else: | ||
lexer = split(arg[:brackets.span()[0]]) | ||
retl = [i.strip(",") for i in lexer] | ||
retl.append(brackets.group()) | ||
return retl | ||
else: | ||
lexer = split(arg[:curly_braces.span()[0]]) | ||
retl = [i.strip(",") for i in lexer] | ||
retl.append(curly_braces.group()) | ||
return retl | ||
|
||
|
||
class HBNBCommand(cmd.Cmd): | ||
"""Defines the HolbertonBnB command interpreter. | ||
Attributes: | ||
prompt (str): The command prompt. | ||
""" | ||
|
||
prompt = "(hbnb) " | ||
__classes = { | ||
"BaseModel", | ||
"User", | ||
"State", | ||
"City", | ||
"Place", | ||
"Amenity", | ||
"Review" | ||
} | ||
|
||
def emptyline(self): | ||
"""Do nothing upon receiving an empty line.""" | ||
pass | ||
|
||
def default(self, arg): | ||
"""Default behavior for cmd module when input is invalid""" | ||
argdict = { | ||
"all": self.do_all, | ||
"show": self.do_show, | ||
"destroy": self.do_destroy, | ||
"count": self.do_count, | ||
"update": self.do_update | ||
} | ||
match = re.search(r"\.", arg) | ||
if match is not None: | ||
argl = [arg[:match.span()[0]], arg[match.span()[1]:]] | ||
match = re.search(r"\((.*?)\)", argl[1]) | ||
if match is not None: | ||
command = [argl[1][:match.span()[0]], match.group()[1:-1]] | ||
if command[0] in argdict.keys(): | ||
call = "{} {}".format(argl[0], command[1]) | ||
return argdict[command[0]](call) | ||
print("*** Unknown syntax: {}".format(arg)) | ||
return False | ||
|
||
def do_quit(self, arg): | ||
"""Quit command to exit the program.""" | ||
return True | ||
|
||
def do_EOF(self, arg): | ||
"""EOF signal to exit the program.""" | ||
print("") | ||
return True | ||
|
||
def do_create(self, arg): | ||
"""Usage: create <class> | ||
Create a new class instance and print its id. | ||
""" | ||
argl = parse(arg) | ||
if len(argl) == 0: | ||
print("** class name missing **") | ||
elif argl[0] not in HBNBCommand.__classes: | ||
print("** class doesn't exist **") | ||
else: | ||
print(eval(argl[0])().id) | ||
storage.save() | ||
|
||
def do_show(self, arg): | ||
"""Usage: show <class> <id> or <class>.show(<id>) | ||
Display the string representation of a class instance of a given id. | ||
""" | ||
argl = parse(arg) | ||
objdict = storage.all() | ||
if len(argl) == 0: | ||
print("** class name missing **") | ||
elif argl[0] not in HBNBCommand.__classes: | ||
print("** class doesn't exist **") | ||
elif len(argl) == 1: | ||
print("** instance id missing **") | ||
elif "{}.{}".format(argl[0], argl[1]) not in objdict: | ||
print("** no instance found **") | ||
else: | ||
print(objdict["{}.{}".format(argl[0], argl[1])]) | ||
|
||
def do_destroy(self, arg): | ||
"""Usage: destroy <class> <id> or <class>.destroy(<id>) | ||
Delete a class instance of a given id.""" | ||
argl = parse(arg) | ||
objdict = storage.all() | ||
if len(argl) == 0: | ||
print("** class name missing **") | ||
elif argl[0] not in HBNBCommand.__classes: | ||
print("** class doesn't exist **") | ||
elif len(argl) == 1: | ||
print("** instance id missing **") | ||
elif "{}.{}".format(argl[0], argl[1]) not in objdict.keys(): | ||
print("** no instance found **") | ||
else: | ||
del objdict["{}.{}".format(argl[0], argl[1])] | ||
storage.save() | ||
|
||
def do_all(self, arg): | ||
"""Usage: all or all <class> or <class>.all() | ||
Display string representations of all instances of a given class. | ||
If no class is specified, displays all instantiated objects.""" | ||
argl = parse(arg) | ||
if len(argl) > 0 and argl[0] not in HBNBCommand.__classes: | ||
print("** class doesn't exist **") | ||
else: | ||
objl = [] | ||
for obj in storage.all().values(): | ||
if len(argl) > 0 and argl[0] == obj.__class__.__name__: | ||
objl.append(obj.__str__()) | ||
elif len(argl) == 0: | ||
objl.append(obj.__str__()) | ||
print(objl) | ||
|
||
def do_count(self, arg): | ||
"""Usage: count <class> or <class>.count() | ||
Retrieve the number of instances of a given class.""" | ||
argl = parse(arg) | ||
count = 0 | ||
for obj in storage.all().values(): | ||
if argl[0] == obj.__class__.__name__: | ||
count += 1 | ||
print(count) | ||
|
||
def do_update(self, arg): | ||
"""Usage: update <class> <id> <attribute_name> <attribute_value> or | ||
<class>.update(<id>, <attribute_name>, <attribute_value>) or | ||
<class>.update(<id>, <dictionary>) | ||
Update a class instance of a given id by adding or updating | ||
a given attribute key/value pair or dictionary.""" | ||
argl = parse(arg) | ||
objdict = storage.all() | ||
|
||
if len(argl) == 0: | ||
print("** class name missing **") | ||
return False | ||
if argl[0] not in HBNBCommand.__classes: | ||
print("** class doesn't exist **") | ||
return False | ||
if len(argl) == 1: | ||
print("** instance id missing **") | ||
return False | ||
if "{}.{}".format(argl[0], argl[1]) not in objdict.keys(): | ||
print("** no instance found **") | ||
return False | ||
if len(argl) == 2: | ||
print("** attribute name missing **") | ||
return False | ||
if len(argl) == 3: | ||
try: | ||
type(eval(argl[2])) != dict | ||
except NameError: | ||
print("** value missing **") | ||
return False | ||
|
||
if len(argl) == 4: | ||
obj = objdict["{}.{}".format(argl[0], argl[1])] | ||
if argl[2] in obj.__class__.__dict__.keys(): | ||
valtype = type(obj.__class__.__dict__[argl[2]]) | ||
obj.__dict__[argl[2]] = valtype(argl[3]) | ||
else: | ||
obj.__dict__[argl[2]] = argl[3] | ||
elif type(eval(argl[2])) == dict: | ||
obj = objdict["{}.{}".format(argl[0], argl[1])] | ||
for k, v in eval(argl[2]).items(): | ||
if (k in obj.__class__.__dict__.keys() and | ||
type(obj.__class__.__dict__[k]) in {str, int, float}): | ||
valtype = type(obj.__class__.__dict__[k]) | ||
obj.__dict__[k] = valtype(v) | ||
else: | ||
obj.__dict__[k] = v | ||
storage.save() | ||
|
||
|
||
if __name__ == "__main__": | ||
HBNBCommand().cmdloop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#!/usr/bin/python3 | ||
"""Module for FileStorage autoinit.""" | ||
|
||
from models.engine.file_storage import FileStorage | ||
storage = FileStorage() | ||
storage.reload() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#!/usr/bin/python3 | ||
"""Module for Amenity class.""" | ||
|
||
from models.base_model import BaseModel | ||
|
||
|
||
class Amenity(BaseModel): | ||
"""Class representing a Amenity.""" | ||
name = "" |
Oops, something went wrong.