diff --git a/0-setup_web_static.sh b/0-setup_web_static.sh
new file mode 100755
index 000000000000..57691d7312c4
--- /dev/null
+++ b/0-setup_web_static.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+# Script that sets up my web servers for the deployment of web_static
+sudo apt-get -y update
+sudo apt-get -y install nginx
+sudo service nginx start
+# Creating parent directories
+sudo mkdir -p /data/web_static/shared/
+sudo mkdir -p /data/web_static/releases/test/
+# Creating a fake HTML file with simple content
+echo 'Rethics' | sudo tee /data/web_static/releases/test/index.html
+#Creating a symbolic link
+ln -sf /data/web_static/releases/test/ /data/web_static/current
+# Giving ownership of the /data/ folder to the ubuntu user AND group
+sudo chown -R ubuntu:ubuntu /data/
+# Updating the Nginx configuration to serve the content of /data/web_static/current/ to hbnb_static
+sed -i "38i location /hbnb_static/ { alias /data/web_static/current/; }" /etc/nginx/sites-available/default
+# Restarting Nginx
+sudo service nginx restart
diff --git a/1-pack_web_static.py b/1-pack_web_static.py
new file mode 100755
index 000000000000..955947171b8a
--- /dev/null
+++ b/1-pack_web_static.py
@@ -0,0 +1,22 @@
+#!/usr/bin/python3
+"""Fabric script that generates a .tgz archive from the contents of the"""
+
+
+from fabric.api import local
+from datetime import datetime
+import os
+
+
+def do_pack():
+ """Generates a .tgz archive from the contents
+ of the web_static folder"""
+ now = datetime.now()
+ now = now.strftime('%Y%m%d%H%M%S')
+ archive_path = 'versions/web_static_' + now + '.tgz'
+
+ local('mkdir -p versions/')
+ result = local('tar -cvzf {} web_static/'.format(archive_path))
+
+ if result.succeeded:
+ return archive_path
+ return None
diff --git a/2-do_deploy_web_static.py b/2-do_deploy_web_static.py
new file mode 100755
index 000000000000..2526b6da036d
--- /dev/null
+++ b/2-do_deploy_web_static.py
@@ -0,0 +1,29 @@
+#!/usr/bin/python3
+"""Fabric script that distributes an archive to your web servers"""
+from fabric.api import env, put, run
+from os.path import exists
+
+env.hosts = ["3.88.201.199", "3.87.90.59"]
+env.user = "ubuntu"
+env.key = "~/.ssh/id_rsa"
+
+
+def do_deploy(archive_path):
+ """Function to distribute an archive to your web servers"""
+ if not exists(archive_path):
+ return False
+ try:
+ file_name = archive_path.split("/")[-1]
+ name = file_name.split(".")[0]
+ path_name = "/data/web_static/releases/" + name
+ put(archive_path, "/tmp/")
+ run("mkdir -p {}/".format(path_name))
+ run('tar -xzf /tmp/{} -C {}/'.format(file_name, path_name))
+ run("rm /tmp/{}".format(file_name))
+ run("mv {}/web_static/* {}".format(path_name, path_name))
+ run("rm -rf {}/web_static".format(path_name))
+ run('rm -rf /data/web_static/current')
+ run('ln -s {}/ /data/web_static/current'.format(path_name))
+ return True
+ except Exception:
+ return False
diff --git a/3-deploy_web_static.py b/3-deploy_web_static.py
new file mode 100755
index 000000000000..af166e3e7e53
--- /dev/null
+++ b/3-deploy_web_static.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python3
+"""Fabric script that creates and distributes an archive to your web servers"""
+
+import os
+from fabric.api import env, local, put, run
+from datetime import datetime
+from os.path import exists
+
+env.hosts = ["98.84.116.96", "3.90.179.12"]
+env.user = "ubuntu"
+env.key = "~/.ssh/id_rsa"
+
+
+def do_pack():
+ """Create a .tgz archive from the web_static folder."""
+ time_stamp = datetime.now().strftime("%Y%m%d%H%M%S")
+ local("mkdir -p versions")
+ archive_path = "versions/web_static_{}.tgz".format(time_stamp)
+ local("tar -cvzf {} web_static".format(archive_path))
+ if os.path.exists(archive_path):
+ return archive_path
+ else:
+ return None
+
+
+def do_deploy(archive_path):
+ """Distribute the archive to web servers and deploy it."""
+ if not exists(archive_path):
+ return False
+ try:
+ file_name = archive_path.split("/")[-1]
+ name = file_name.split(".")[0]
+ path_name = "/data/web_static/releases/" + name
+ put(archive_path, "/tmp/")
+ run("mkdir -p {}/".format(path_name))
+ run('tar -xzf /tmp/{} -C {}/'.format(file_name, path_name))
+ run("rm /tmp/{}".format(file_name))
+ run("mv {}/web_static/* {}".format(path_name, path_name))
+ run("rm -rf {}/web_static".format(path_name))
+ run('rm -rf /data/web_static/current')
+ run('ln -s {}/ /data/web_static/current'.format(path_name))
+ return True
+ except Exception:
+ return False
+
+
+def deploy():
+ """Create and distribute an archive to web servers."""
+ archive_path = do_pack()
+ if not archive_path:
+ return False
+
+ return do_deploy(archive_path)
diff --git a/README.md b/README.md
index 3ce462902d67..e99203d32913 100644
--- a/README.md
+++ b/README.md
@@ -1,142 +1,818 @@
-
HBNB - The Console
-
-This repository contains the initial stage of a student project to build a clone of the AirBnB website. This stage implements a backend interface, or console, to manage program data. Console commands allow the user to create, update, and destroy objects, as well as manage file storage. Using a system of JSON serialization/deserialization, storage is persistent between sessions.
-
----
-
-Repository Contents by Project Task
-
-| Tasks | Files | Description |
-| ----- | ----- | ------ |
-| 0: Authors/README File | [AUTHORS](https://github.com/justinmajetich/AirBnB_clone/blob/dev/AUTHORS) | Project authors |
-| 1: Pep8 | N/A | All code is pep8 compliant|
-| 2: Unit Testing | [/tests](https://github.com/justinmajetich/AirBnB_clone/tree/dev/tests) | All class-defining modules are unittested |
-| 3. Make BaseModel | [/models/base_model.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/models/base_model.py) | Defines a parent class to be inherited by all model classes|
-| 4. Update BaseModel w/ kwargs | [/models/base_model.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/models/base_model.py) | Add functionality to recreate an instance of a class from a dictionary representation|
-| 5. Create FileStorage class | [/models/engine/file_storage.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/models/engine/file_storage.py) [/models/_ _init_ _.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/models/__init__.py) [/models/base_model.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/models/base_model.py) | Defines a class to manage persistent file storage system|
-| 6. Console 0.0.1 | [console.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/console.py) | Add basic functionality to console program, allowing it to quit, handle empty lines and ^D |
-| 7. Console 0.1 | [console.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/console.py) | Update the console with methods allowing the user to create, destroy, show, and update stored data |
-| 8. Create User class | [console.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/console.py) [/models/engine/file_storage.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/models/engine/file_storage.py) [/models/user.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/models/user.py) | Dynamically implements a user class |
-| 9. More Classes | [/models/user.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/models/user.py) [/models/place.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/models/place.py) [/models/city.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/models/city.py) [/models/amenity.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/models/amenity.py) [/models/state.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/models/state.py) [/models/review.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/models/review.py) | Dynamically implements more classes |
-| 10. Console 1.0 | [console.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/console.py) [/models/engine/file_storage.py](https://github.com/justinmajetich/AirBnB_clone/blob/dev/models/engine/file_storage.py) | Update the console and file storage system to work dynamically with all classes update file storage |
-
-
- General Use
-
-1. First clone this repository.
-
-3. Once the repository is cloned locate the "console.py" file and run it as follows:
-```
-/AirBnB_clone$ ./console.py
-```
-4. When this command is run the following prompt should appear:
-```
+Concepts
+For this project, we expect you to look at this concept:
+
+AirBnB clone
+Background Context
+Environment variables will be your best friend for this project!
+
+HBNB_ENV: running environment. It can be “dev” or “test” for the moment (“production” soon!)
+HBNB_MYSQL_USER: the username of your MySQL
+HBNB_MYSQL_PWD: the password of your MySQL
+HBNB_MYSQL_HOST: the hostname of your MySQL
+HBNB_MYSQL_DB: the database name of your MySQL
+HBNB_TYPE_STORAGE: the type of storage used. It can be “file” (using FileStorage) or db (using DBStorage)
+Resources
+Read or watch:
+
+cmd module
+packages concept page
+unittest module
+args/kwargs
+SQLAlchemy tutorial
+How To Create a New User and Grant Permissions in MySQL
+Python3 and environment variables
+SQLAlchemy
+MySQL 8.0 SQL Statement Syntax
+AirBnB clone - ORM
+Learning Objectives
+At the end of this project, you are expected to be able to explain to anyone, without the help of Google:
+
+General
+What is Unit testing and how to implement it in a large project
+What is *args and how to use it
+What is **kwargs and how to use it
+How to handle named arguments in a function
+How to create a MySQL database
+How to create a MySQL user and grant it privileges
+What ORM means
+How to map a Python Class to a MySQL table
+How to handle 2 different storage engines with the same codebase
+How to use environment variables
+Requirements
+Python Scripts
+Allowed editors: vi, vim, emacs
+All your files will be interpreted/compiled on Ubuntu 20.04 LTS using python3 (version 3.8.5)
+All your files should end with a new line
+The first line of all your files should be exactly #!/usr/bin/python3
+A README.md file, at the root of the folder of the project, is mandatory
+Your code should use the pycodestyle (version 2.7.*)
+All your files must be executable
+The length of your files will be tested using wc
+All your modules should have documentation (python3 -c 'print(__import__("my_module").__doc__)')
+All your classes should have documentation (python3 -c 'print(__import__("my_module").MyClass.__doc__)')
+All your functions (inside and outside a class) should have documentation (python3 -c 'print(__import__("my_module").my_function.__doc__)' and python3 -c 'print(__import__("my_module").MyClass.my_function.__doc__)')
+A documentation is not a simple word, it’s a real sentence explaining what’s the purpose of the module, class or method (the length of it will be verified)
+Python Unit Tests
+Allowed editors: vi, vim, emacs
+All your files should end with a new line
+All your test files should be inside a folder tests
+You have to use the unittest module
+All your test files should be python files (extension: .py)
+All your test files and folders should start by test_
+Your file organization in the tests folder should be the same as your project: ex: for models/base_model.py, unit tests must be in: tests/test_models/test_base_model.py
+All your tests should be executed by using this command: python3 -m unittest discover tests
+You can also test file by file by using this command: python3 -m unittest tests/test_models/test_base_model.py
+All your modules should have documentation (python3 -c 'print(__import__("my_module").__doc__)')
+All your classes should have documentation (python3 -c 'print(__import__("my_module").MyClass.__doc__)')
+All your functions (inside and outside a class) should have documentation (python3 -c 'print(__import__("my_module").my_function.__doc__)' and python3 -c 'print(__import__("my_module").MyClass.my_function.__doc__)')
+We strongly encourage you to work together on test cases, so that you don’t miss any edge cases
+SQL Scripts
+Allowed editors: vi, vim, emacs
+All your files will be executed on Ubuntu 20.04 LTS using MySQL 8.0
+Your files will be executed with SQLAlchemy version 1.4.x
+All your files should end with a new line
+All your SQL queries should have a comment just before (i.e. syntax above)
+All your files should start by a comment describing the task
+All SQL keywords should be in uppercase (SELECT, WHERE…)
+A README.md file, at the root of the folder of the project, is mandatory
+The length of your files will be tested using wc
+GitHub
+There should be one project repository per group. If you clone/fork/whatever a partner’s project repository with the same name before the second deadline, you risk a 0% score.
+
+More Info
+
+
+
+Comments for your SQL file:
+$ cat my_script.sql
+-- first 3 students in the Batch ID=3
+-- because Batch 3 is the best!
+SELECT id, name FROM students WHERE batch_id = 3 ORDER BY created_at DESC LIMIT 3;
+$
+Tasks
+0. Fork me if you can!
+mandatory
+In the industry, you will work on an existing codebase 90% of the time. Your first thoughts upon looking at it might include:
+
+“Who did this code?”
+“How it works?”
+“Where are unittests?”
+“Where is this?”
+“Why did they do that like this?”
+“I don’t understand anything.”
+“… I will refactor everything…”
+But the worst thing you could possibly do is to redo everything. Please don’t do that! Note: the existing codebase might be perfect, or it might have errors. Don’t always trust the existing codebase!
+
+For this project you will fork this codebase:
+
+update the repository name (specified in the section Repo)
+update the README.md with your information but don’t delete the initial authors
+Repo:
+
+GitHub repository: alu-AirBnB_clone_v2
+
+0/12 pts
+1. Bug free!
+mandatory
+Do you remember the unittest module?
+
+This codebase contains many test cases. Some are missing, but the ones included cover the basic functionality of the program.
+
+guillaume@ubuntu:~/AirBnB_v2$ python3 -m unittest discover tests 2>&1 /dev/null | tail -n 1
+OK
+guillaume@ubuntu:~/AirBnB_v2$
+All your unittests must pass without any errors at anytime in this project, with each storage engine!. Same for PEP8!
+
+guillaume@ubuntu:~/AirBnB_v2$ HBNB_ENV=test HBNB_MYSQL_USER=hbnb_test HBNB_MYSQL_PWD=hbnb_test_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_test_db HBNB_TYPE_STORAGE=db python3 -m unittest discover tests 2>&1 /dev/null | tail -n 1
+OK
+guillaume@ubuntu:~/AirBnB_v2$
+Some tests won’t be relevant for some type of storage, please skip them by using the skipIf feature of the Unittest module - 26.3.6. Skipping tests and expected failures. Of course, the number of tests must be higher than the current number of tests, so if you decide to skip a test, you should write a new test!
+
+How to test with MySQL?
+First, you create a specific database for it (next tasks). After, you have to remember what the purpose of an unittest?
+
+“Assert a current state (objects/data/database), do an action, and validate this action changed (or not) the state of your objects/data/database”
+
+For example, “you want to validate that the create State name="California" command in the console will add a new record in your table states in your database”, here steps for your unittest:
+
+get the number of current records in the table states (my using a MySQLdb for example - but not SQLAlchemy (remember, you want to test if it works, so it’s better to isolate from the system))
+execute the console command
+get (again) the number of current records in the table states (same method, with MySQLdb)
+if the difference is +1 => test passed
+Repo:
+
+GitHub repository: alu-AirBnB_clone_v2
+
+0/36 pts
+2. Console improvements
+mandatory
+Update the def do_create(self, arg): function of your command interpreter (console.py) to allow for object creation with given parameters:
+
+Command syntax: create ...
+Param syntax: =
+Value syntax:
+String: "" => starts with a double quote
+any double quote inside the value must be escaped with a backslash \
+all underscores _ must be replace by spaces . Example: You want to set the string My little house to the attribute name, your command line must be name="My_little_house"
+Float: . => contains a dot .
+Integer: => default case
+If any parameter doesn’t fit with these requirements or can’t be recognized correctly by your program, it must be skipped
+Don’t forget to add tests for this new feature!
+
+Also, this new feature will be tested here only with FileStorage engine.
+
+guillaume@ubuntu:~/AirBnB_v2$ cat test_params_create
+create State name="California"
+create State name="Arizona"
+all State
+
+create Place city_id="0001" user_id="0001" name="My_little_house" number_rooms=4 number_bathrooms=2 max_guest=10 price_by_night=300 latitude=37.773972 longitude=-122.431297
+all Place
+guillaume@ubuntu:~/AirBnB_v2$ cat test_params_create | ./console.py
+(hbnb) d80e0344-63eb-434a-b1e0-07783522124e
+(hbnb) 092c9e5d-6cc0-4eec-aab9-3c1d79cfc2d7
+(hbnb) [[State] (d80e0344-63eb-434a-b1e0-07783522124e) {'id': 'd80e0344-63eb-434a-b1e0-07783522124e', 'created_at': datetime.datetime(2017, 11, 10, 4, 41, 7, 842160), 'updated_at': datetime.datetime(2017, 11, 10, 4, 41, 7, 842235), 'name': 'California'}, [State] (092c9e5d-6cc0-4eec-aab9-3c1d79cfc2d7) {'id': '092c9e5d-6cc0-4eec-aab9-3c1d79cfc2d7', 'created_at': datetime.datetime(2017, 11, 10, 4, 41, 7, 842779), 'updated_at': datetime.datetime(2017, 11, 10, 4, 41, 7, 842792), 'name': 'Arizona'}]
+(hbnb) (hbnb) 76b65327-9e94-4632-b688-aaa22ab8a124
+(hbnb) [[Place] (76b65327-9e94-4632-b688-aaa22ab8a124) {'number_bathrooms': 2, 'longitude': -122.431297, 'city_id': '0001', 'user_id': '0001', 'latitude': 37.773972, 'price_by_night': 300, 'name': 'My little house', 'id': '76b65327-9e94-4632-b688-aaa22ab8a124', 'max_guest': 10, 'number_rooms': 4, 'updated_at': datetime.datetime(2017, 11, 10, 4, 41, 7, 843774), 'created_at': datetime.datetime(2017, 11, 10, 4, 41, 7, 843747)}]
(hbnb)
-```
-5. This prompt designates you are in the "HBnB" console. There are a variety of commands available within the console program.
-
-##### Commands
- * create - Creates an instance based on given class
-
- * destroy - Destroys an object based on class and UUID
-
- * show - Shows an object based on class and UUID
-
- * all - Shows all objects the program has access to, or all objects of a given class
-
- * update - Updates existing attributes an object based on class name and UUID
-
- * quit - Exits the program (EOF will as well)
-
-
-##### Alternative Syntax
-Users are able to issue a number of console command using an alternative syntax:
-
- Usage: .([[name_arg value_arg]|[kwargs]])
-Advanced syntax is implemented for the following commands:
-
- * all - Shows all objects the program has access to, or all objects of a given class
-
- * count - Return number of object instances by class
-
- * show - Shows an object based on class and UUID
-
- * destroy - Destroys an object based on class and UUID
-
- * update - Updates existing attributes an object based on class name and UUID
-
-
-
- Examples
-Primary Command Syntax
-
-###### Example 0: Create an object
-Usage: create
-```
-(hbnb) create BaseModel
-```
-```
-(hbnb) create BaseModel
-3aa5babc-efb6-4041-bfe9-3cc9727588f8
-(hbnb)
-```
-###### Example 1: Show an object
-Usage: show <_id>
-
-```
-(hbnb) show BaseModel 3aa5babc-efb6-4041-bfe9-3cc9727588f8
-[BaseModel] (3aa5babc-efb6-4041-bfe9-3cc9727588f8) {'id': '3aa5babc-efb6-4041-bfe9-3cc9727588f8', 'created_at': datetime.datetime(2020, 2, 18, 14, 21, 12, 96959),
-'updated_at': datetime.datetime(2020, 2, 18, 14, 21, 12, 96971)}
-(hbnb)
-```
-###### Example 2: Destroy an object
-Usage: destroy <_id>
-```
-(hbnb) destroy BaseModel 3aa5babc-efb6-4041-bfe9-3cc9727588f8
-(hbnb) show BaseModel 3aa5babc-efb6-4041-bfe9-3cc9727588f8
-** no instance found **
-(hbnb)
-```
-###### Example 3: Update an object
-Usage: update <_id>
-```
-(hbnb) update BaseModel b405fc64-9724-498f-b405-e4071c3d857f first_name "person"
-(hbnb) show BaseModel b405fc64-9724-498f-b405-e4071c3d857f
-[BaseModel] (b405fc64-9724-498f-b405-e4071c3d857f) {'id': 'b405fc64-9724-498f-b405-e4071c3d857f', 'created_at': datetime.datetime(2020, 2, 18, 14, 33, 45, 729889),
-'updated_at': datetime.datetime(2020, 2, 18, 14, 33, 45, 729907), 'first_name': 'person'}
+guillaume@ubuntu:~/AirBnB_v2$
+Repo:
+
+GitHub repository: alu-AirBnB_clone_v2
+File: console.py, models/, tests/
+
+0/22 pts
+3. MySQL setup development
+mandatory
+Write a script that prepares a MySQL server for the project:
+
+A database hbnb_dev_db
+A new user hbnb_dev (in localhost)
+The password of hbnb_dev should be set to hbnb_dev_pwd
+hbnb_dev should have all privileges on the database hbnb_dev_db (and only this database)
+hbnb_dev should have SELECT privilege on the database performance_schema (and only this database)
+If the database hbnb_dev_db or the user hbnb_dev already exists, your script should not fail
+guillaume@ubuntu:~/AirBnB_v2$ cat setup_mysql_dev.sql | mysql -hlocalhost -uroot -p
+Enter password:
+guillaume@ubuntu:~/AirBnB_v2$ echo "SHOW DATABASES;" | mysql -uhbnb_dev -p | grep hbnb_dev_db
+Enter password:
+hbnb_dev_db
+guillaume@ubuntu:~/AirBnB_v2$ echo "SHOW GRANTS FOR 'hbnb_dev'@'localhost';" | mysql -uroot -p
+Enter password:
+Grants for hbnb_dev@localhost
+GRANT USAGE ON *.* TO 'hbnb_dev'@'localhost'
+GRANT SELECT ON `performance_schema`.* TO 'hbnb_dev'@'localhost'
+GRANT ALL PRIVILEGES ON `hbnb_dev_db`.* TO 'hbnb_dev'@'localhost'
+guillaume@ubuntu:~/AirBnB_v2$
+Repo:
+
+GitHub repository: alu-AirBnB_clone_v2
+File: setup_mysql_dev.sql
+
+0/21 pts
+4. MySQL setup test
+mandatory
+Write a script that prepares a MySQL server for the project:
+
+A database hbnb_test_db
+A new user hbnb_test (in localhost)
+The password of hbnb_test should be set to hbnb_test_pwd
+hbnb_test should have all privileges on the database hbnb_test_db (and only this database)
+hbnb_test should have SELECT privilege on the database performance_schema (and only this database)
+If the database hbnb_test_db or the user hbnb_test already exists, your script should not fail
+guillaume@ubuntu:~/AirBnB_v2$ cat setup_mysql_test.sql | mysql -hlocalhost -uroot -p
+Enter password:
+guillaume@ubuntu:~/AirBnB_v2$ echo "SHOW DATABASES;" | mysql -uhbnb_test -p | grep hbnb_test_db
+Enter password:
+hbnb_test_db
+guillaume@ubuntu:~/AirBnB_v2$ echo "SHOW GRANTS FOR 'hbnb_test'@'localhost';" | mysql -uroot -p
+Enter password:
+Grants for hbnb_test@localhost
+GRANT USAGE ON *.* TO 'hbnb_test'@'localhost'
+GRANT SELECT ON `performance_schema`.* TO 'hbnb_test'@'localhost'
+GRANT ALL PRIVILEGES ON `hbnb_test_db`.* TO 'hbnb_test'@'localhost'
+guillaume@ubuntu:~/AirBnB_v2$
+Repo:
+
+GitHub repository: alu-AirBnB_clone_v2
+File: setup_mysql_test.sql
+
+0/21 pts
+5. Delete object
+mandatory
+Update FileStorage: (models/engine/file_storage.py)
+
+Add a new public instance method: def delete(self, obj=None): to delete obj from __objects if it’s inside - if obj is equal to None, the method should not do anything
+Update the prototype of def all(self) to def all(self, cls=None) - that returns the list of objects of one type of class. Example below with State - it’s an optional filtering
+guillaume@ubuntu:~/AirBnB_v2$ cat main_delete.py
+#!/usr/bin/python3
+""" Test delete feature
+"""
+from models.engine.file_storage import FileStorage
+from models.state import State
+
+fs = FileStorage()
+
+# All States
+all_states = fs.all(State)
+print("All States: {}".format(len(all_states.keys())))
+for state_key in all_states.keys():
+ print(all_states[state_key])
+
+# Create a new State
+new_state = State()
+new_state.name = "California"
+fs.new(new_state)
+fs.save()
+print("New State: {}".format(new_state))
+
+# All States
+all_states = fs.all(State)
+print("All States: {}".format(len(all_states.keys())))
+for state_key in all_states.keys():
+ print(all_states[state_key])
+
+# Create another State
+another_state = State()
+another_state.name = "Nevada"
+fs.new(another_state)
+fs.save()
+print("Another State: {}".format(another_state))
+
+# All States
+all_states = fs.all(State)
+print("All States: {}".format(len(all_states.keys())))
+for state_key in all_states.keys():
+ print(all_states[state_key])
+
+# Delete the new State
+fs.delete(new_state)
+
+# All States
+all_states = fs.all(State)
+print("All States: {}".format(len(all_states.keys())))
+for state_key in all_states.keys():
+ print(all_states[state_key])
+
+guillaume@ubuntu:~/AirBnB_v2$ ./main_delete.py
+All States: 0
+New State: [State] (b0026fc6-116f-4d1a-a9cb-6bb9b299f1ce) {'name': 'California', 'created_at': datetime.datetime(2017, 11, 10, 1, 13, 32, 561137), 'id': 'b0026fc6-116f-4d1a-a9cb-6bb9b299f1ce'}
+All States: 1
+[State] (b0026fc6-116f-4d1a-a9cb-6bb9b299f1ce) {'name': 'California', 'created_at': datetime.datetime(2017, 11, 10, 1, 13, 32, 561137), 'id': 'b0026fc6-116f-4d1a-a9cb-6bb9b299f1ce'}
+Another State: [State] (37705d25-8903-4318-9303-6d6d336a22c1) {'name': 'Nevada', 'created_at': datetime.datetime(2017, 11, 10, 1, 13, 34, 619133), 'id': '37705d25-8903-4318-9303-6d6d336a22c1'}
+All States: 2
+[State] (b0026fc6-116f-4d1a-a9cb-6bb9b299f1ce) {'name': 'California', 'created_at': datetime.datetime(2017, 11, 10, 1, 13, 32, 561137), 'id': 'b0026fc6-116f-4d1a-a9cb-6bb9b299f1ce'}
+[State] (37705d25-8903-4318-9303-6d6d336a22c1) {'name': 'Nevada', 'created_at': datetime.datetime(2017, 11, 10, 1, 13, 34, 619133), 'id': '37705d25-8903-4318-9303-6d6d336a22c1'}
+All States: 1
+[State] (37705d25-8903-4318-9303-6d6d336a22c1) {'name': 'Nevada', 'created_at': datetime.datetime(2017, 11, 10, 1, 13, 34, 619133), 'id': '37705d25-8903-4318-9303-6d6d336a22c1'}
+guillaume@ubuntu:~/AirBnB_v2$
+Repo:
+
+GitHub repository: alu-AirBnB_clone_v2
+File: models/engine/file_storage.py
+
+0/17 pts
+6. DBStorage - States and Cities
+mandatory
+SQLAlchemy will be your best friend!
+
+It’s time to change your storage engine and use SQLAlchemy
+
+
+
+In the following steps, you will make multiple changes:
+
+the biggest one is the transition between FileStorage and DBStorage: In the industry, you will never find a system who can work with both in the same time - but you will find a lot of services who can manage multiple storage systems. (for example, logs service: in memory, in disk, in database, in ElasticSearch etc…) - The main concept behind is the abstraction: Make your code running without knowing how it’s stored.
+add attributes for SQLAlchemy: they will be class attributes, like previously, with a “weird” value. Don’t worry, these values are for description and mapping to the database. If you change one of these values, or add/remove one attribute of the a model, you will have to delete the database and recreate it in SQL. (Yes it’s not optimal, but for development purposes, it’s ok. In production, we will add “migration mechanism” - for the moment, don’t spend time on it.)
+Please follow all these steps:
+
+Update BaseModel: (models/base_model.py)
+
+Create Base = declarative_base() before the class definition of BaseModel
+Note! BaseModel does /not/ inherit from Base. All other classes will inherit from BaseModel to get common values (id, created_at, updated_at), where inheriting from Base will actually cause SQLAlchemy to attempt to map it to a table.
+Add or replace in the class BaseModel:
+class attribute id
+represents a column containing a unique string (60 characters)
+can’t be null
+primary key
+class attribute created_at
+represents a column containing a datetime
+can’t be null
+default value is the current datetime (use datetime.utcnow())
+class attribute updated_at
+represents a column containing a datetime
+can’t be null
+default value is the current datetime (use datetime.utcnow())
+Move the models.storage.new(self) from def __init__(self, *args, **kwargs): to def save(self): and call it just before models.storage.save()
+In def __init__(self, *args, **kwargs):, manage kwargs to create instance attribute from this dictionary. Ex: kwargs={ 'name': "California" } => self.name = "California" if it’s not already the case
+Update the to_dict() method of the class BaseModel:
+remove the key _sa_instance_state from the dictionary returned by this method only if this key exists
+Add a new public instance method: def delete(self): to delete the current instance from the storage (models.storage) by calling the method delete
+Update City: (models/city.py)
+
+City inherits from BaseModel and Base (respect the order)
+Add or replace in the class City:
+class attribute __tablename__ -
+represents the table name, cities
+class attribute name
+represents a column containing a string (128 characters)
+can’t be null
+class attribute state_id
+represents a column containing a string (60 characters)
+can’t be null
+is a foreign key to states.id
+Update State: (models/state.py)
+
+State inherits from BaseModel and Base (respect the order)
+Add or replace in the class State:
+class attribute __tablename__
+represents the table name, states
+class attribute name
+represents a column containing a string (128 characters)
+can’t be null
+for DBStorage: class attribute cities must represent a relationship with the class City. If the State object is deleted, all linked City objects must be automatically deleted. Also, the reference from a City object to his State should be named state
+for FileStorage: getter attribute cities that returns the list of City instances with state_id equals to the current State.id => It will be the FileStorage relationship between State and City
+New engine DBStorage: (models/engine/db_storage.py)
+
+Private class attributes:
+__engine: set to None
+__session: set to None
+Public instance methods:
+__init__(self):
+create the engine (self.__engine)
+the engine must be linked to the MySQL database and user created before (hbnb_dev and hbnb_dev_db):
+dialect: mysql
+driver: mysqldb
+all of the following values must be retrieved via environment variables:
+MySQL user: HBNB_MYSQL_USER
+MySQL password: HBNB_MYSQL_PWD
+MySQL host: HBNB_MYSQL_HOST (here = localhost)
+MySQL database: HBNB_MYSQL_DB
+don’t forget the option pool_pre_ping=True when you call create_engine
+drop all tables if the environment variable HBNB_ENV is equal to test
+all(self, cls=None):
+query on the current database session (self.__session) all objects depending of the class name (argument cls)
+if cls=None, query all types of objects (User, State, City, Amenity, Place and Review)
+this method must return a dictionary: (like FileStorage)
+key = .
+value = object
+new(self, obj): add the object to the current database session (self.__session)
+save(self): commit all changes of the current database session (self.__session)
+delete(self, obj=None): delete from the current database session obj if not None
+reload(self):
+create all tables in the database (feature of SQLAlchemy) (WARNING: all classes who inherit from Base must be imported before calling Base.metadata.create_all(engine))
+create the current database session (self.__session) from the engine (self.__engine) by using a sessionmaker - the option expire_on_commit must be set to False ; and scoped_session - to make sure your Session is thread-safe
+Update __init__.py: (models/__init__.py)
+
+Add a conditional depending of the value of the environment variable HBNB_TYPE_STORAGE:
+If equal to db:
+Import DBStorage class in this file
+Create an instance of DBStorage and store it in the variable storage (the line storage.reload() should be executed after this instantiation)
+Else:
+Import FileStorage class in this file
+Create an instance of FileStorage and store it in the variable storage (the line storage.reload() should be executed after this instantiation)
+This “switch” will allow you to change storage type directly by using an environment variable (example below)
+State creation:
+
+guillaume@ubuntu:~/AirBnB_v2$ echo 'create State name="California"' | HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db ./console.py
+(hbnb) 95a5abab-aa65-4861-9bc6-1da4a36069aa
(hbnb)
-```
-Alternative Syntax
-
-###### Example 0: Show all User objects
-Usage: .all()
-```
-(hbnb) User.all()
-["[User] (99f45908-1d17-46d1-9dd2-b7571128115b) {'updated_at': datetime.datetime(2020, 2, 19, 21, 47, 34, 92071), 'id': '99f45908-1d17-46d1-9dd2-b7571128115b', 'created_at': datetime.datetime(2020, 2, 19, 21, 47, 34, 92056)}", "[User] (98bea5de-9cb0-4d78-8a9d-c4de03521c30) {'updated_at': datetime.datetime(2020, 2, 19, 21, 47, 29, 134362), 'id': '98bea5de-9cb0-4d78-8a9d-c4de03521c30', 'created_at': datetime.datetime(2020, 2, 19, 21, 47, 29, 134343)}"]
-```
-
-###### Example 1: Destroy a User
-Usage: .destroy(<_id>)
-```
-(hbnb) User.destroy("99f45908-1d17-46d1-9dd2-b7571128115b")
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'all State' | HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db ./console.py
+(hbnb) [[State] (95a5abab-aa65-4861-9bc6-1da4a36069aa) {'name': 'California', 'id': '95a5abab-aa65-4861-9bc6-1da4a36069aa', 'updated_at': datetime.datetime(2017, 11, 10, 0, 49, 54), 'created_at': datetime.datetime(2017, 11, 10, 0, 49, 54)}]
+(hbnb)
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'SELECT * FROM states\G' | mysql -uhbnb_dev -p hbnb_dev_db
+Enter password:
+*************************** 1. row ***************************
+ id: 95a5abab-aa65-4861-9bc6-1da4a36069aa
+created_at: 2017-11-10 00:49:54
+updated_at: 2017-11-10 00:49:54
+ name: California
+guillaume@ubuntu:~/AirBnB_v2$
+City creation:
+
+guillaume@ubuntu:~/AirBnB_v2$ echo 'create City state_id="95a5abab-aa65-4861-9bc6-1da4a36069aa" name="San_Francisco"' | HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db ./console.py
+(hbnb) 4b457e66-c7c8-4f63-910f-fd91c3b7140b
(hbnb)
-(hbnb) User.all()
-(hbnb) ["[User] (98bea5de-9cb0-4d78-8a9d-c4de03521c30) {'updated_at': datetime.datetime(2020, 2, 19, 21, 47, 29, 134362), 'id': '98bea5de-9cb0-4d78-8a9d-c4de03521c30', 'created_at': datetime.datetime(2020, 2, 19, 21, 47, 29, 134343)}"]
-```
-###### Example 2: Update User (by attribute)
-Usage: .update(<_id>, , )
-```
-(hbnb) User.update("98bea5de-9cb0-4d78-8a9d-c4de03521c30", name "Todd the Toad")
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'all City' | HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db ./console.py
+(hbnb) [[City] (4b457e66-c7c8-4f63-910f-fd91c3b7140b) {'id': '4b457e66-c7c8-4f63-910f-fd91c3b7140b', 'updated_at': datetime.datetime(2017, 11, 10, 0, 52, 53), 'state_id': '95a5abab-aa65-4861-9bc6-1da4a36069aa', 'name': 'San Francisco', 'created_at': datetime.datetime(2017, 11, 10, 0, 52, 53)]
(hbnb)
-(hbnb) User.all()
-(hbnb) ["[User] (98bea5de-9cb0-4d78-8a9d-c4de03521c30) {'updated_at': datetime.datetime(2020, 2, 19, 21, 47, 29, 134362), 'id': '98bea5de-9cb0-4d78-8a9d-c4de03521c30', 'name': 'Todd the Toad', 'created_at': datetime.datetime(2020, 2, 19, 21, 47, 29, 134343)}"]
-```
-###### Example 3: Update User (by dictionary)
-Usage: .update(<_id>, )
-```
-(hbnb) User.update("98bea5de-9cb0-4d78-8a9d-c4de03521c30", {'name': 'Fred the Frog', 'age': 9})
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'create City state_id="95a5abab-aa65-4861-9bc6-1da4a36069aa" name="San_Jose"' | HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db ./console.py
+(hbnb) a7db3cdc-30e0-4d80-ad8c-679fe45343ba
(hbnb)
-(hbnb) User.all()
-(hbnb) ["[User] (98bea5de-9cb0-4d78-8a9d-c4de03521c30) {'updated_at': datetime.datetime(2020, 2, 19, 21, 47, 29, 134362), 'name': 'Fred the Frog', 'age': 9, 'id': '98bea5de-9cb0-4d78-8a9d-c4de03521c30', 'created_at': datetime.datetime(2020, 2, 19, 21, 47, 29, 134343)}"]
-```
-
\ No newline at end of file
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'SELECT * FROM cities\G' | mysql -uhbnb_dev -p hbnb_dev_db
+Enter password:
+*************************** 1. row ***************************
+ id: 4b457e66-c7c8-4f63-910f-fd91c3b7140b
+created_at: 2017-11-10 00:52:53
+updated_at: 2017-11-10 00:52:53
+ name: San Francisco
+ state_id: 95a5abab-aa65-4861-9bc6-1da4a36069aa
+*************************** 2. row ***************************
+ id: a7db3cdc-30e0-4d80-ad8c-679fe45343ba
+created_at: 2017-11-10 00:53:19
+updated_at: 2017-11-10 00:53:19
+ name: San Jose
+ state_id: 95a5abab-aa65-4861-9bc6-1da4a36069aa
+guillaume@ubuntu:~/AirBnB_v2$
+Repo:
+
+GitHub repository: alu-AirBnB_clone_v2
+File: models/base_model.py, models/city.py, models/state.py, models/engine/db_storage.py, models/__init__.py
+
+0/16 pts
+7. DBStorage - User
+mandatory
+Update User: (models/user.py)
+
+User inherits from BaseModel and Base (respect the order)
+Add or replace in the class User:
+class attribute __tablename__
+represents the table name, users
+class attribute email
+represents a column containing a string (128 characters)
+can’t be null
+class attribute password
+represents a column containing a string (128 characters)
+can’t be null
+class attribute first_name
+represents a column containing a string (128 characters)
+can be null
+class attribute last_name
+represents a column containing a string (128 characters)
+can be null
+guillaume@ubuntu:~/AirBnB_v2$ echo 'create User email="gui@hbtn.io" password="guipwd" first_name="Guillaume" last_name="Snow"' | HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db ./console.py
+(hbnb) 4f3f4b42-a4c3-4c20-a492-efff10d00c0b
+(hbnb)
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'all User' | HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db ./console.py
+(hbnb) [[User] (4f3f4b42-a4c3-4c20-a492-efff10d00c0b) {'updated_at': datetime.datetime(2017, 11, 10, 1, 17, 26), 'id': '4f3f4b42-a4c3-4c20-a492-efff10d00c0b', 'last_name': 'Snow', 'first_name': 'Guillaume', 'email': 'gui@hbtn.io', 'created_at': datetime.datetime(2017, 11, 10, 1, 17, 26), 'password': 'f4ce007d8e84e0910fbdd7a06fa1692d'}]
+(hbnb)
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'SELECT * FROM users\G' | mysql -uhbnb_dev -p hbnb_dev_db
+Enter password:
+*************************** 1. row ***************************
+ id: 4f3f4b42-a4c3-4c20-a492-efff10d00c0b
+created_at: 2017-11-10 01:17:26
+updated_at: 2017-11-10 01:17:26
+ email: gui@hbtn.io
+ password: guipwd
+first_name: Guillaume
+ last_name: Snow
+guillaume@ubuntu:~/AirBnB_v2$
+Repo:
+
+GitHub repository: alu-AirBnB_clone_v2
+File: models/user.py
+
+0/9 pts
+8. DBStorage - Place
+mandatory
+Update Place: (models/place.py)
+
+Place inherits from BaseModel and Base (respect the order)
+Add or replace in the class Place:
+class attribute __tablename__
+represents the table name, places
+class attribute city_id
+represents a column containing a string (60 characters)
+can’t be null
+is a foreign key to cities.id
+class attribute user_id
+represents a column containing a string (60 characters)
+can’t be null
+is a foreign key to users.id
+class attribute name
+represents a column containing a string (128 characters)
+can’t be null
+class attribute description
+represents a column containing a string (1024 characters)
+can be null
+class attribute number_rooms
+represents a column containing an integer
+can’t be null
+default value: 0
+class attribute number_bathrooms
+represents a column containing an integer
+can’t be null
+default value: 0
+class attribute max_guest
+represents a column containing an integer
+can’t be null
+default value: 0
+class attribute price_by_night
+represents a column containing an integer
+can’t be null
+default value: 0
+class attribute latitude
+represents a column containing a float
+can be null
+class attribute longitude
+represents a column containing a float
+can be null
+Update User: (models/user.py)
+
+Add or replace in the class User:
+class attribute places must represent a relationship with the class Place. If the User object is deleted, all linked Place objects must be automatically deleted. Also, the reference from a Place object to his User should be named user
+Update City: (models/city.py)
+
+Add or replace in the class City:
+class attribute places must represent a relationship with the class Place. If the City object is deleted, all linked Place objects must be automatically deleted. Also, the reference from a Place object to his City should be named cities
+guillaume@ubuntu:~/AirBnB_v2$ echo 'create Place city_id="4b457e66-c7c8-4f63-910f-fd91c3b7140b" user_id="4f3f4b42-a4c3-4c20-a492-efff10d00c0b" name="Lovely_place" number_rooms=3 number_bathrooms=1 max_guest=6 price_by_night=120 latitude=37.773972 longitude=-122.431297' | HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db ./console.py
+(hbnb) ed72aa02-3286-4891-acbc-9d9fc80a1103
+(hbnb)
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'all Place' | HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db ./console.py
+(hbnb) [[Place] (ed72aa02-3286-4891-acbc-9d9fc80a1103) {'latitude': 37.774, 'city_id': '4b457e66-c7c8-4f63-910f-fd91c3b7140b', 'price_by_night': 120, 'id': 'ed72aa02-3286-4891-acbc-9d9fc80a1103', 'user_id': '4f3f4b42-a4c3-4c20-a492-efff10d00c0b', 'max_guest': 6, 'created_at': datetime.datetime(2017, 11, 10, 1, 22, 30), 'description': None, 'number_rooms': 3, 'longitude': -122.431, 'number_bathrooms': 1, 'name': '"Lovely place', 'updated_at': datetime.datetime(2017, 11, 10, 1, 22, 30)}]
+(hbnb)
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'SELECT * FROM places\G' | mysql -uhbnb_dev -p hbnb_dev_db
+Enter password:
+*************************** 1. row ***************************
+ id: ed72aa02-3286-4891-acbc-9d9fc80a1103
+ created_at: 2017-11-10 01:22:30
+ updated_at: 2017-11-10 01:22:30
+ city_id: 4b457e66-c7c8-4f63-910f-fd91c3b7140b
+ user_id: 4f3f4b42-a4c3-4c20-a492-efff10d00c0b
+ name: "Lovely place"
+ description: NULL
+ number_rooms: 3
+number_bathrooms: 1
+ max_guest: 6
+ price_by_night: 120
+ latitude: 37.774
+ longitude: -122.431
+guillaume@ubuntu:~/AirBnB_v2$
+Repo:
+
+GitHub repository: alu-AirBnB_clone_v2
+File: models/place.py, models/user.py, models/city.py
+
+0/16 pts
+9. DBStorage - Review
+mandatory
+Update Review: (models/review.py)
+
+Review inherits from BaseModel and Base (respect the order)
+Add or replace in the class Review:
+class attribute __tablename__
+represents the table name, reviews
+class attribute text
+represents a column containing a string (1024 characters)
+can’t be null
+class attribute place_id
+represents a column containing a string (60 characters)
+can’t be null
+is a foreign key to places.id
+class attribute user_id
+represents a column containing a string (60 characters)
+can’t be null
+is a foreign key to users.id
+Update User: (models/user.py)
+
+Add or replace in the class User:
+class attribute reviews must represent a relationship with the class Review. If the User object is deleted, all linked Review objects must be automatically deleted. Also, the reference from a Review object to his User should be named user
+Update Place: (models/place.py)
+
+for DBStorage: class attribute reviews must represent a relationship with the class Review. If the Place object is deleted, all linked Review objects must be automatically deleted. Also, the reference from a Review object to his Place should be named place
+for FileStorage: getter attribute reviews that returns the list of Review instances with place_id equals to the current Place.id => It will be the FileStorage relationship between Place and Review
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'create User email="bob@hbtn.io" password="bobpwd" first_name="Bob" last_name="Dylan"' | HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db ./console.py
+(hbnb) d93638d9-8233-4124-8f4e-17786592908b
+(hbnb)
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'create Review place_id="ed72aa02-3286-4891-acbc-9d9fc80a1103" user_id="d93638d9-8233-4124-8f4e-17786592908b" text="Amazing_place,_huge_kitchen"' | HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db ./console.py
+(hbnb) a2d163d3-1982-48ab-a06b-9dc71e68a791
+(hbnb)
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'all Review' | HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db ./console.py
+(hbnb) [[Review] (f2616ff2-f723-4d67-85dc-f050a38e0f2f) {'text': 'Amazing place, huge kitchen', 'place_id': 'ed72aa02-3286-4891-acbc-9d9fc80a1103', 'id': 'f2616ff2-f723-4d67-85dc-f050a38e0f2f', 'updated_at': datetime.datetime(2017, 11, 10, 4, 6, 25), 'created_at': datetime.datetime(2017, 11, 10, 4, 6, 25), 'user_id': 'd93638d9-8233-4124-8f4e-17786592908b'}]
+(hbnb)
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'SELECT * FROM reviews\G' | mysql -uhbnb_dev -p hbnb_dev_db
+Enter password:
+*************************** 1. row ***************************
+ id: f2616ff2-f723-4d67-85dc-f050a38e0f2f
+created_at: 2017-11-10 04:06:25
+updated_at: 2017-11-10 04:06:25
+ text: Amazing place, huge kitchen
+ place_id: ed72aa02-3286-4891-acbc-9d9fc80a1103
+ user_id: d93638d9-8233-4124-8f4e-17786592908b
+guillaume@ubuntu:~/AirBnB_v2$
+Repo:
+
+GitHub repository: alu-AirBnB_clone_v2
+File: models/review.py, models/user.py, models/place.py
+
+0/10 pts
+10. DBStorage - Amenity... and BOOM!
+mandatory
+Update Amenity: (models/amenity.py)
+
+Amenity inherits from BaseModel and Base (respect the order)
+Add or replace in the class Amenity:
+class attribute __tablename__
+represents the table name, amenities
+class attribute name
+represents a column containing a string (128 characters)
+can’t be null
+class attribute place_amenities must represent a relationship Many-To-Many between the class Place and Amenity. Please see below more detail: place_amenity in the Place update
+Update Place: (models/place.py)
+
+Add an instance of SQLAlchemy Table called place_amenity for creating the relationship Many-To-Many between Place and Amenity:
+table name place_amenity
+metadata = Base.metadata
+2 columns:
+place_id, a string of 60 characters foreign key of places.id, primary key in the table and never null
+amenity_id, a string of 60 characters foreign key of amenities.id, primary key in the table and never null
+Update Place class:
+for DBStorage: class attribute amenities must represent a relationship with the class Amenity but also as secondary to place_amenity with option viewonly=False (place_amenity has been define previously)
+for FileStorage:
+Getter attribute amenities that returns the list of Amenity instances based on the attribute amenity_ids that contains all Amenity.id linked to the Place
+Setter attribute amenities that handles append method for adding an Amenity.id to the attribute amenity_ids. This method should accept only Amenity object, otherwise, do nothing.
+What’s a Many-to-Many relationship?
+In our system, we don’t want to duplicate amenities (for example, having 10000 time the amenity Wifi), so they will be unique. But, at least 2 places can have the same amenity (like Wifi for example). We are in the case of:
+
+an amenity can be linked to multiple places
+a place can have multiple amenities
+= Many-To-Many
+
+To make this link working, we will create a third table called place_amenity that will create these links.
+
+And you are good, you have a new engine!
+
+guillaume@ubuntu:~/AirBnB_v2$ cat main_place_amenities.py
+#!/usr/bin/python3
+""" Test link Many-To-Many Place <> Amenity
+"""
+from models import *
+
+# creation of a State
+state = State(name="California")
+state.save()
+
+# creation of a City
+city = City(state_id=state.id, name="San Francisco")
+city.save()
+
+# creation of a User
+user = User(email="john@snow.com", password="johnpwd")
+user.save()
+
+# creation of 2 Places
+place_1 = Place(user_id=user.id, city_id=city.id, name="House 1")
+place_1.save()
+place_2 = Place(user_id=user.id, city_id=city.id, name="House 2")
+place_2.save()
+
+# creation of 3 various Amenity
+amenity_1 = Amenity(name="Wifi")
+amenity_1.save()
+amenity_2 = Amenity(name="Cable")
+amenity_2.save()
+amenity_3 = Amenity(name="Oven")
+amenity_3.save()
+
+# link place_1 with 2 amenities
+place_1.amenities.append(amenity_1)
+place_1.amenities.append(amenity_2)
+
+# link place_2 with 3 amenities
+place_2.amenities.append(amenity_1)
+place_2.amenities.append(amenity_2)
+place_2.amenities.append(amenity_3)
+
+storage.save()
+
+print("OK")
+
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ HBNB_MYSQL_USER=hbnb_dev HBNB_MYSQL_PWD=hbnb_dev_pwd HBNB_MYSQL_HOST=localhost HBNB_MYSQL_DB=hbnb_dev_db HBNB_TYPE_STORAGE=db ./main_place_amenities.py
+OK
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'SELECT * FROM amenities\G' | mysql -uhbnb_dev -p hbnb_dev_db
+Enter password:
+*************************** 1. row ***************************
+ id: 47321eb8-152a-46df-969a-440aa67a6d59
+created_at: 2017-11-10 04:22:02
+updated_at: 2017-11-10 04:22:02
+ name: Cable
+*************************** 2. row ***************************
+ id: 4a307e7f-68f9-438f-81c0-8325898dda2a
+created_at: 2017-11-10 04:22:02
+updated_at: 2017-11-10 04:22:02
+ name: Oven
+*************************** 3. row ***************************
+ id: b80aec52-d0c9-420a-8471-3254572954b6
+created_at: 2017-11-10 04:22:02
+updated_at: 2017-11-10 04:22:02
+ name: Wifi
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'SELECT * FROM places\G' | mysql -uhbnb_dev -p hbnb_dev_db
+Enter password:
+*************************** 1. row ***************************
+ id: 497e3867-d6e9-4401-9c7c-9687c18d2ac7
+ created_at: 2017-11-10 04:22:02
+ updated_at: 2017-11-10 04:22:02
+ city_id: 9d60df6e-31f7-430c-8162-69e89f4a17aa
+ user_id: 9b37bd51-6aef-485f-bf10-c7ab83fea2e9
+ name: House 1
+ description: NULL
+ number_rooms: 0
+number_bathrooms: 0
+ max_guest: 0
+ price_by_night: 0
+ latitude: NULL
+ longitude: NULL
+*************************** 2. row ***************************
+ id: db549ae1-4500-4d0c-9b50-4b4978ed229e
+ created_at: 2017-11-10 04:22:02
+ updated_at: 2017-11-10 04:22:02
+ city_id: 9d60df6e-31f7-430c-8162-69e89f4a17aa
+ user_id: 9b37bd51-6aef-485f-bf10-c7ab83fea2e9
+ name: House 2
+ description: NULL
+ number_rooms: 0
+number_bathrooms: 0
+ max_guest: 0
+ price_by_night: 0
+ latitude: NULL
+ longitude: NULL
+guillaume@ubuntu:~/AirBnB_v2$
+guillaume@ubuntu:~/AirBnB_v2$ echo 'SELECT * FROM place_amenity\G' | mysql -uhbnb_dev -p hbnb_dev_db
+Enter password:
+*************************** 1. row ***************************
+ place_id: 497e3867-d6e9-4401-9c7c-9687c18d2ac7
+amenity_id: 47321eb8-152a-46df-969a-440aa67a6d59
+*************************** 2. row ***************************
+ place_id: db549ae1-4500-4d0c-9b50-4b4978ed229e
+amenity_id: 47321eb8-152a-46df-969a-440aa67a6d59
+*************************** 3. row ***************************
+ place_id: db549ae1-4500-4d0c-9b50-4b4978ed229e
+amenity_id: 4a307e7f-68f9-438f-81c0-8325898dda2a
+*************************** 4. row ***************************
+ place_id: 497e3867-d6e9-4401-9c7c-9687c18d2ac7
+amenity_id: b80aec52-d0c9-420a-8471-3254572954b6
+*************************** 5. row ***************************
+ place_id: db549ae1-4500-4d0c-9b50-4b4978ed229e
+amenity_id: b80aec52-d0c9-420a-8471-3254572954b6
+guillaume@ubuntu:~/AirBnB_v2$
+Repo:
+
+GitHub repository: alu-AirBnB_clone_v2
+File: models/amenity.py, models/place.py
+
+0/11 pts
+Score
+Project badge
+0%
+Your score will be updated once you launch the project review.
+
+Please review all the tasks before you start the peer review.
+
+Previous project
+
diff --git a/console.py b/console.py
index 13a8af68e930..6c4b5606f057 100755
--- a/console.py
+++ b/console.py
@@ -1,324 +1,272 @@
#!/usr/bin/python3
-""" Console Module """
+"""Defines the HBNB console."""
import cmd
-import sys
+from shlex import split
+from models import storage
+from datetime import datetime
from models.base_model import BaseModel
-from models.__init__ import storage
from models.user import User
-from models.place import Place
from models.state import State
from models.city import City
from models.amenity import Amenity
+from models.place import Place
from models.review import Review
class HBNBCommand(cmd.Cmd):
- """ Contains the functionality for the HBNB console"""
-
- # determines prompt for interactive/non-interactive modes
- prompt = '(hbnb) ' if sys.__stdin__.isatty() else ''
+ """Defines the HolbertonBnB command interpreter."""
+
+ prompt = "(hbnb) "
+ __classes = {
+ "BaseModel",
+ "User",
+ "State",
+ "City",
+ "Amenity",
+ "Place",
+ "Review"
+ }
- classes = {
- 'BaseModel': BaseModel, 'User': User, 'Place': Place,
- 'State': State, 'City': City, 'Amenity': Amenity,
- 'Review': Review
- }
- dot_cmds = ['all', 'count', 'show', 'destroy', 'update']
- types = {
- 'number_rooms': int, 'number_bathrooms': int,
- 'max_guest': int, 'price_by_night': int,
- 'latitude': float, 'longitude': float
- }
+ def emptyline(self):
+ """Ignore empty spaces."""
+ pass
- def preloop(self):
- """Prints if isatty is false"""
- if not sys.__stdin__.isatty():
- print('(hbnb)')
+ def do_quit(self, line):
+ """Quit command to exit the program."""
+ return True
- def precmd(self, line):
- """Reformat command line for advanced command syntax.
+ def do_EOF(self, line):
+ """EOF signal to exit the program."""
+ print("")
+ return True
- Usage: .([ [<*args> or <**kwargs>]])
- (Brackets denote optional fields in usage example.)
+ def do_create(self, line):
+ """Usage: create = = ...
+ Create a new class instance with given keys/values and print its id.
"""
- _cmd = _cls = _id = _args = '' # initialize line elements
-
- # scan for general formating - i.e '.', '(', ')'
- if not ('.' in line and '(' in line and ')' in line):
- return line
-
- try: # parse line left to right
- pline = line[:] # parsed line
-
- # isolate
- _cls = pline[:pline.find('.')]
-
- # isolate and validate
- _cmd = pline[pline.find('.') + 1:pline.find('(')]
- if _cmd not in HBNBCommand.dot_cmds:
- raise Exception
-
- # if parantheses contain arguments, parse them
- pline = pline[pline.find('(') + 1:pline.find(')')]
- if pline:
- # partition args: (, [], [<*args>])
- pline = pline.partition(', ') # pline convert to tuple
-
- # isolate _id, stripping quotes
- _id = pline[0].replace('\"', '')
- # possible bug here:
- # empty quotes register as empty _id when replaced
-
- # if arguments exist beyond _id
- pline = pline[2].strip() # pline is now str
- if pline:
- # check for *args or **kwargs
- if pline[0] is '{' and pline[-1] is'}'\
- and type(eval(pline)) is dict:
- _args = pline
- else:
- _args = pline.replace(',', '')
- # _args = _args.replace('\"', '')
- line = ' '.join([_cmd, _cls, _id, _args])
-
- except Exception as mess:
- pass
- finally:
- return line
-
- def postcmd(self, stop, line):
- """Prints if isatty is false"""
- if not sys.__stdin__.isatty():
- print('(hbnb) ', end='')
- return stop
-
- def do_quit(self, command):
- """ Method to exit the HBNB console"""
- exit()
-
- def help_quit(self):
- """ Prints the help documentation for quit """
- print("Exits the program with formatting\n")
-
- def do_EOF(self, arg):
- """ Handles EOF to exit program """
- print()
- exit()
-
- def help_EOF(self):
- """ Prints the help documentation for EOF """
- print("Exits the program without formatting\n")
-
- def emptyline(self):
- """ Overrides the emptyline method of CMD """
- pass
-
- def do_create(self, args):
- """ Create an object of any class"""
- if not args:
+ try:
+ if not line:
+ raise SyntaxError()
+ my_list = line.split(" ")
+
+ kwargs = {}
+ for i in range(1, len(my_list)):
+ key, value = tuple(my_list[i].split("="))
+ if value[0] == '"':
+ value = value.strip('"').replace("_", " ")
+ else:
+ try:
+ value = eval(value)
+ except (SyntaxError, NameError):
+ continue
+ kwargs[key] = value
+
+ if kwargs == {}:
+ obj = eval(my_list[0])()
+ else:
+ obj = eval(my_list[0])(**kwargs)
+ storage.new(obj)
+ print(obj.id)
+ obj.save()
+
+ except SyntaxError:
print("** class name missing **")
- return
- elif args not in HBNBCommand.classes:
+ except NameError:
print("** class doesn't exist **")
- return
- new_instance = HBNBCommand.classes[args]()
- storage.save()
- print(new_instance.id)
- storage.save()
-
- def help_create(self):
- """ Help information for the create method """
- print("Creates a class of any type")
- print("[Usage]: create \n")
- def do_show(self, args):
- """ Method to show an individual object """
- new = args.partition(" ")
- c_name = new[0]
- c_id = new[2]
-
- # guard against trailing args
- if c_id and ' ' in c_id:
- c_id = c_id.partition(' ')[0]
-
- if not c_name:
+ def do_show(self, line):
+ """Prints the string representation of an instance
+ Exceptions:
+ SyntaxError: when there is no args given
+ NameError: when there is no object taht has the name
+ IndexError: when there is no id given
+ KeyError: when there is no valid id given
+ """
+ try:
+ if not line:
+ raise SyntaxError()
+ my_list = line.split(" ")
+ if my_list[0] not in self.__classes:
+ raise NameError()
+ if len(my_list) < 2:
+ raise IndexError()
+ objects = storage.all()
+ key = my_list[0] + '.' + my_list[1]
+ if key in objects:
+ print(objects[key])
+ else:
+ raise KeyError()
+ except SyntaxError:
print("** class name missing **")
- return
-
- if c_name not in HBNBCommand.classes:
+ except NameError:
print("** class doesn't exist **")
- return
-
- if not c_id:
+ except IndexError:
print("** instance id missing **")
- return
-
- key = c_name + "." + c_id
- try:
- print(storage._FileStorage__objects[key])
except KeyError:
print("** no instance found **")
- def help_show(self):
- """ Help information for the show command """
- print("Shows an individual instance of a class")
- print("[Usage]: show \n")
-
- def do_destroy(self, args):
- """ Destroys a specified object """
- new = args.partition(" ")
- c_name = new[0]
- c_id = new[2]
- if c_id and ' ' in c_id:
- c_id = c_id.partition(' ')[0]
-
- if not c_name:
+ def do_destroy(self, line):
+ """Deletes an instance based on the class name and id
+ Exceptions:
+ SyntaxError: when there is no args given
+ NameError: when there is no object taht has the name
+ IndexError: when there is no id given
+ KeyError: when there is no valid id given
+ """
+ try:
+ if not line:
+ raise SyntaxError()
+ my_list = line.split(" ")
+ if my_list[0] not in self.__classes:
+ raise NameError()
+ if len(my_list) < 2:
+ raise IndexError()
+ objects = storage.all()
+ key = my_list[0] + '.' + my_list[1]
+ if key in objects:
+ del objects[key]
+ storage.save()
+ else:
+ raise KeyError()
+ except SyntaxError:
print("** class name missing **")
- return
-
- if c_name not in HBNBCommand.classes:
+ except NameError:
print("** class doesn't exist **")
- return
-
- if not c_id:
+ except IndexError:
print("** instance id missing **")
- return
-
- key = c_name + "." + c_id
-
- try:
- del(storage.all()[key])
- storage.save()
except KeyError:
print("** no instance found **")
- def help_destroy(self):
- """ Help information for the destroy command """
- print("Destroys an individual instance of a class")
- print("[Usage]: destroy \n")
-
- def do_all(self, args):
- """ Shows all objects, or all objects of a class"""
- print_list = []
-
- if args:
- args = args.split(' ')[0] # remove possible trailing args
- if args not in HBNBCommand.classes:
- print("** class doesn't exist **")
- return
- for k, v in storage._FileStorage__objects.items():
- if k.split('.')[0] == args:
- print_list.append(str(v))
- else:
- for k, v in storage._FileStorage__objects.items():
- print_list.append(str(v))
-
- print(print_list)
-
- def help_all(self):
- """ Help information for the all command """
- print("Shows all objects, or all of a class")
- print("[Usage]: all \n")
-
- def do_count(self, args):
- """Count current number of class instances"""
- count = 0
- for k, v in storage._FileStorage__objects.items():
- if args == k.split('.')[0]:
- count += 1
- print(count)
+ def do_all(self, line):
+ """Usage: all or all or .all()
+ Display string representations of all instances of a given class.
+ If no class is specified, displays all instantiated objects."""
+ if not line:
+ o = storage.all()
+ print([o[k].__str__() for k in o])
+ return
+ try:
+ args = line.split(" ")
+ if args[0] not in self.__classes:
+ raise NameError()
- def help_count(self):
- """ """
- print("Usage: count ")
+ o = storage.all(eval(args[0]))
+ print([o[k].__str__() for k in o])
- def do_update(self, args):
- """ Updates a certain object with new info """
- c_name = c_id = att_name = att_val = kwargs = ''
+ except NameError:
+ print("** class doesn't exist **")
- # isolate cls from id/args, ex: (, delim, )
- args = args.partition(" ")
- if args[0]:
- c_name = args[0]
- else: # class name not present
+ def do_update(self, line):
+ """Updates an instanceby adding or updating attribute
+ Exceptions:
+ SyntaxError: when there is no args given
+ NameError: when there is no object taht has the name
+ IndexError: when there is no id given
+ KeyError: when there is no valid id given
+ AttributeError: when there is no attribute given
+ ValueError: when there is no value given
+ """
+ try:
+ if not line:
+ raise SyntaxError()
+ my_list = split(line, " ")
+ if my_list[0] not in self.__classes:
+ raise NameError()
+ if len(my_list) < 2:
+ raise IndexError()
+ objects = storage.all()
+ key = my_list[0] + '.' + my_list[1]
+ if key not in objects:
+ raise KeyError()
+ if len(my_list) < 3:
+ raise AttributeError()
+ if len(my_list) < 4:
+ raise ValueError()
+ v = objects[key]
+ try:
+ v.__dict__[my_list[2]] = eval(my_list[3])
+ except Exception:
+ v.__dict__[my_list[2]] = my_list[3]
+ v.save()
+ except SyntaxError:
print("** class name missing **")
- return
- if c_name not in HBNBCommand.classes: # class name invalid
+ except NameError:
print("** class doesn't exist **")
- return
-
- # isolate id from args
- args = args[2].partition(" ")
- if args[0]:
- c_id = args[0]
- else: # id not present
+ except IndexError:
print("** instance id missing **")
- return
-
- # generate key from class and id
- key = c_name + "." + c_id
-
- # determine if key is present
- if key not in storage.all():
+ except KeyError:
print("** no instance found **")
- return
-
- # first determine if kwargs or args
- if '{' in args[2] and '}' in args[2] and type(eval(args[2])) is dict:
- kwargs = eval(args[2])
- args = [] # reformat kwargs into list, ex: [, , ...]
- for k, v in kwargs.items():
- args.append(k)
- args.append(v)
- else: # isolate args
- args = args[2]
- if args and args[0] is '\"': # check for quoted arg
- second_quote = args.find('\"', 1)
- att_name = args[1:second_quote]
- args = args[second_quote + 1:]
-
- args = args.partition(' ')
-
- # if att_name was not quoted arg
- if not att_name and args[0] is not ' ':
- att_name = args[0]
- # check for quoted val arg
- if args[2] and args[2][0] is '\"':
- att_val = args[2][1:args[2].find('\"', 1)]
-
- # if att_val was not quoted arg
- if not att_val and args[2]:
- att_val = args[2].partition(' ')[0]
+ except AttributeError:
+ print("** attribute name missing **")
+ except ValueError:
+ print("** value missing **")
- args = [att_name, att_val]
-
- # retrieve dictionary of current objects
- new_dict = storage.all()[key]
-
- # iterate through attr names and values
- for i, att_name in enumerate(args):
- # block only runs on even iterations
- if (i % 2 == 0):
- att_val = args[i + 1] # following item is value
- if not att_name: # check for att_name
- print("** attribute name missing **")
- return
- if not att_val: # check for att_value
- print("** value missing **")
- return
- # type cast as necessary
- if att_name in HBNBCommand.types:
- att_val = HBNBCommand.types[att_name](att_val)
-
- # update dictionary with name, value pair
- new_dict.__dict__.update({att_name: att_val})
+ def count(self, line):
+ """count the number of instances of a class
+ """
+ counter = 0
+ try:
+ my_list = split(line, " ")
+ if my_list[0] not in self.__classes:
+ raise NameError()
+ objects = storage.all()
+ for key in objects:
+ name = key.split('.')
+ if name[0] == my_list[0]:
+ counter += 1
+ print(counter)
+ except NameError:
+ print("** class doesn't exist **")
- new_dict.save() # save updates to file
+ def strip_clean(self, args):
+ """strips the argument and return a string of command
+ Args:
+ args: input list of args
+ Return:
+ returns string of argumetns
+ """
+ new_list = []
+ new_list.append(args[0])
+ try:
+ my_dict = eval(
+ args[1][args[1].find('{'):args[1].find('}')+1])
+ except Exception:
+ my_dict = None
+ if isinstance(my_dict, dict):
+ new_str = args[1][args[1].find('(')+1:args[1].find(')')]
+ new_list.append(((new_str.split(", "))[0]).strip('"'))
+ new_list.append(my_dict)
+ return new_list
+ new_str = args[1][args[1].find('(')+1:args[1].find(')')]
+ new_list.append(" ".join(new_str.split(", ")))
+ return " ".join(i for i in new_list)
+
+ def default(self, line):
+ """retrieve all instances of a class and
+ retrieve the number of instances
+ """
+ my_list = line.split('.')
+ if len(my_list) >= 2:
+ if my_list[1] == "all()":
+ self.do_all(my_list[0])
+ elif my_list[1] == "count()":
+ self.count(my_list[0])
+ elif my_list[1][:4] == "show":
+ self.do_show(self.strip_clean(my_list))
+ elif my_list[1][:7] == "destroy":
+ self.do_destroy(self.strip_clean(my_list))
+ elif my_list[1][:6] == "update":
+ args = self.strip_clean(my_list)
+ if isinstance(args, list):
+ obj = storage.all()
+ key = args[0] + ' ' + args[1]
+ for k, v in args[2].items():
+ self.do_update(key + ' "{}" "{}"'.format(k, v))
+ else:
+ self.do_update(args)
+ else:
+ cmd.Cmd.default(self, line)
- def help_update(self):
- """ Help information for the update class """
- print("Updates an object with new information")
- print("Usage: update \n")
-if __name__ == "__main__":
+if __name__ == '__main__':
HBNBCommand().cmdloop()
diff --git a/models/__init__.py b/models/__init__.py
old mode 100644
new mode 100755
index d3765c2bc603..e0912aa884e9
--- a/models/__init__.py
+++ b/models/__init__.py
@@ -1,7 +1,19 @@
#!/usr/bin/python3
-"""This module instantiates an object of class FileStorage"""
+"""create a unique FileStorage instance for your application"""
from models.engine.file_storage import FileStorage
+from models.engine.db_storage import DBStorage
+from models.base_model import BaseModel
+from models.user import User
+from models.state import State
+from models.city import City
+from models.amenity import Amenity
+from models.place import Place
+from models.review import Review
+from os import getenv
-storage = FileStorage()
+if getenv("HBNB_TYPE_STORAGE") == "db":
+ storage = DBStorage()
+else:
+ storage = FileStorage()
storage.reload()
diff --git a/models/amenity.py b/models/amenity.py
old mode 100644
new mode 100755
index a181095e4170..dcf66a55a39e
--- a/models/amenity.py
+++ b/models/amenity.py
@@ -1,7 +1,16 @@
#!/usr/bin/python3
-""" State Module for HBNB project """
-from models.base_model import BaseModel
+"""This is the amenity class"""
+from models.base_model import BaseModel, Base
+from sqlalchemy.orm import relationship
+from sqlalchemy import Column, String
+from models.place import place_amenity
-class Amenity(BaseModel):
- name = ""
+class Amenity(BaseModel, Base):
+ """This is the class for Amenity
+ Attributes:
+ name: input name
+ """
+ __tablename__ = "amenities"
+ name = Column(String(128), nullable=False)
+ place_amenities = relationship("Place", secondary=place_amenity)
diff --git a/models/base_model.py b/models/base_model.py
old mode 100644
new mode 100755
index 4856e9de421f..937901ff28e9
--- a/models/base_model.py
+++ b/models/base_model.py
@@ -1,44 +1,83 @@
#!/usr/bin/python3
-"""This module defines a base class for all models in our hbnb clone"""
+"""This is the base model class for AirBnB"""
+from sqlalchemy.ext.declarative import declarative_base
import uuid
+import models
from datetime import datetime
+from sqlalchemy import Column, Integer, String, DateTime
+
+
+Base = declarative_base()
class BaseModel:
- """A base class for all hbnb models"""
+ """This class will defines all common attributes/methods
+ for other classes
+ """
+ id = Column(String(60), unique=True, nullable=False, primary_key=True)
+ created_at = Column(DateTime, nullable=False, default=(datetime.utcnow()))
+ updated_at = Column(DateTime, nullable=False, default=(datetime.utcnow()))
+
def __init__(self, *args, **kwargs):
- """Instatntiates a new model"""
- if not kwargs:
- from models import storage
- self.id = str(uuid.uuid4())
- self.created_at = datetime.now()
- self.updated_at = datetime.now()
- storage.new(self)
+ """Instantiation of base model class
+ Args:
+ args: it won't be used
+ kwargs: arguments for the constructor of the BaseModel
+ Attributes:
+ id: unique id generated
+ created_at: creation date
+ updated_at: updated date
+ """
+ if kwargs:
+ for key, value in kwargs.items():
+ if key == "created_at" or key == "updated_at":
+ value = datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%f")
+ if key != "__class__":
+ setattr(self, key, value)
+ if "id" not in kwargs:
+ self.id = str(uuid.uuid4())
+ if "created_at" not in kwargs:
+ self.created_at = datetime.now()
+ if "updated_at" not in kwargs:
+ self.updated_at = datetime.now()
else:
- kwargs['updated_at'] = datetime.strptime(kwargs['updated_at'],
- '%Y-%m-%dT%H:%M:%S.%f')
- kwargs['created_at'] = datetime.strptime(kwargs['created_at'],
- '%Y-%m-%dT%H:%M:%S.%f')
- del kwargs['__class__']
- self.__dict__.update(kwargs)
+ self.id = str(uuid.uuid4())
+ self.created_at = self.updated_at = datetime.now()
def __str__(self):
- """Returns a string representation of the instance"""
- cls = (str(type(self)).split('.')[-1]).split('\'')[0]
- return '[{}] ({}) {}'.format(cls, self.id, self.__dict__)
+ """returns a string
+ Return:
+ returns a string of class name, id, and dictionary
+ """
+ return "[{}] ({}) {}".format(
+ type(self).__name__, self.id, self.__dict__)
+
+ def __repr__(self):
+ """return a string representaion
+ """
+ return self.__str__()
def save(self):
- """Updates updated_at with current time when instance is changed"""
- from models import storage
+ """updates the public instance attribute updated_at to current
+ """
self.updated_at = datetime.now()
- storage.save()
+ models.storage.new(self)
+ models.storage.save()
def to_dict(self):
- """Convert instance into dict format"""
- dictionary = {}
- dictionary.update(self.__dict__)
- dictionary.update({'__class__':
- (str(type(self)).split('.')[-1]).split('\'')[0]})
- dictionary['created_at'] = self.created_at.isoformat()
- dictionary['updated_at'] = self.updated_at.isoformat()
- return dictionary
+ """creates dictionary of the class and returns
+ Return:
+ returns a dictionary of all the key values in __dict__
+ """
+ my_dict = dict(self.__dict__)
+ my_dict["__class__"] = str(type(self).__name__)
+ my_dict["created_at"] = self.created_at.isoformat()
+ my_dict["updated_at"] = self.updated_at.isoformat()
+ if '_sa_instance_state' in my_dict.keys():
+ del my_dict['_sa_instance_state']
+ return my_dict
+
+ def delete(self):
+ """ delete object
+ """
+ models.storage.delete(self)
diff --git a/models/city.py b/models/city.py
old mode 100644
new mode 100755
index b9b4fe221502..041d5bf94e6b
--- a/models/city.py
+++ b/models/city.py
@@ -1,9 +1,21 @@
#!/usr/bin/python3
-""" City Module for HBNB project """
-from models.base_model import BaseModel
+"""This is the city class"""
+from sqlalchemy.ext.declarative import declarative_base
+from models.base_model import BaseModel, Base
+from sqlalchemy import Column, Integer, String
+from sqlalchemy import ForeignKey
+from sqlalchemy.orm import relationship
+from models.place import Place
-class City(BaseModel):
- """ The city class, contains state ID and name """
- state_id = ""
- name = ""
+class City(BaseModel, Base):
+ """This is the class for City
+ Attributes:
+ state_id: The state id
+ name: input name
+ """
+ __tablename__ = "cities"
+ name = Column(String(128), nullable=False)
+ state_id = Column(String(60), ForeignKey('states.id'), nullable=False)
+ places = relationship("Place", cascade='all, delete, delete-orphan',
+ backref="cities")
diff --git a/models/engine/__init__.py b/models/engine/__init__.py
old mode 100644
new mode 100755
diff --git a/models/engine/db_storage.py b/models/engine/db_storage.py
new file mode 100755
index 000000000000..43e97b056d50
--- /dev/null
+++ b/models/engine/db_storage.py
@@ -0,0 +1,84 @@
+#!/usr/bin/python3
+""" new class for sqlAlchemy """
+from os import getenv
+from sqlalchemy.orm import sessionmaker, scoped_session
+from sqlalchemy import (create_engine)
+from sqlalchemy.ext.declarative import declarative_base
+from models.base_model import Base
+from models.state import State
+from models.city import City
+from models.user import User
+from models.place import Place
+from models.review import Review
+from models.amenity import Amenity
+
+
+class DBStorage:
+ """ create tables in environmental"""
+ __engine = None
+ __session = None
+
+ def __init__(self):
+ user = getenv("HBNB_MYSQL_USER")
+ passwd = getenv("HBNB_MYSQL_PWD")
+ db = getenv("HBNB_MYSQL_DB")
+ host = getenv("HBNB_MYSQL_HOST")
+ env = getenv("HBNB_ENV")
+
+ self.__engine = create_engine('mysql+mysqldb://{}:{}@{}/{}'
+ .format(user, passwd, host, db),
+ pool_pre_ping=True)
+
+ if env == "test":
+ Base.metadata.drop_all(self.__engine)
+
+ def all(self, cls=None):
+ """returns a dictionary
+ Return:
+ returns a dictionary of __object
+ """
+ dic = {}
+ if cls:
+ if type(cls) is str:
+ cls = eval(cls)
+ query = self.__session.query(cls)
+ for elem in query:
+ key = "{}.{}".format(type(elem).__name__, elem.id)
+ dic[key] = elem
+ else:
+ lista = [State, City, User, Place, Review, Amenity]
+ for clase in lista:
+ query = self.__session.query(clase)
+ for elem in query:
+ key = "{}.{}".format(type(elem).__name__, elem.id)
+ dic[key] = elem
+ return (dic)
+
+ def new(self, obj):
+ """add a new element in the table
+ """
+ self.__session.add(obj)
+
+ def save(self):
+ """save changes
+ """
+ self.__session.commit()
+
+ def delete(self, obj=None):
+ """delete an element in the table
+ """
+ if obj:
+ self.session.delete(obj)
+
+ def reload(self):
+ """configuration
+ """
+ Base.metadata.create_all(self.__engine)
+ sec = sessionmaker(bind=self.__engine, expire_on_commit=False)
+ Session = scoped_session(sec)
+ self.__session = Session()
+
+ def close(self):
+ """ calls remove()
+ """
+ self.__session.close()
diff --git a/models/engine/file_storage.py b/models/engine/file_storage.py
old mode 100644
new mode 100755
index 6f5d7f8d4680..60196ed0bb36
--- a/models/engine/file_storage.py
+++ b/models/engine/file_storage.py
@@ -1,50 +1,80 @@
#!/usr/bin/python3
-"""This module defines a class to manage file storage for hbnb clone"""
+"""This is the file storage class for AirBnB"""
import json
+from models.base_model import BaseModel
+from models.user import User
+from models.state import State
+from models.city import City
+from models.amenity import Amenity
+from models.place import Place
+from models.review import Review
+import shlex
class FileStorage:
- """This class manages storage of hbnb models in JSON format"""
- __file_path = 'file.json'
+ """This class serializes instances to a JSON file and
+ deserializes JSON file to instances
+ Attributes:
+ __file_path: path to the JSON file
+ __objects: objects will be stored
+ """
+ __file_path = "file.json"
__objects = {}
- def all(self):
- """Returns a dictionary of models currently in storage"""
- return FileStorage.__objects
+ def all(self, cls=None):
+ """returns a dictionary
+ Return:
+ returns a dictionary of __object
+ """
+ dic = {}
+ if cls:
+ dictionary = self.__objects
+ for key in dictionary:
+ partition = key.replace('.', ' ')
+ partition = shlex.split(partition)
+ if (partition[0] == cls.__name__):
+ dic[key] = self.__objects[key]
+ return (dic)
+ else:
+ return self.__objects
def new(self, obj):
- """Adds new object to storage dictionary"""
- self.all().update({obj.to_dict()['__class__'] + '.' + obj.id: obj})
+ """sets __object to given obj
+ Args:
+ obj: given object
+ """
+ if obj:
+ key = "{}.{}".format(type(obj).__name__, obj.id)
+ self.__objects[key] = obj
def save(self):
- """Saves storage dictionary to file"""
- with open(FileStorage.__file_path, 'w') as f:
- temp = {}
- temp.update(FileStorage.__objects)
- for key, val in temp.items():
- temp[key] = val.to_dict()
- json.dump(temp, f)
+ """serialize the file path to JSON file path
+ """
+ my_dict = {}
+ for key, value in self.__objects.items():
+ my_dict[key] = value.to_dict()
+ with open(self.__file_path, 'w', encoding="UTF-8") as f:
+ json.dump(my_dict, f)
def reload(self):
- """Loads storage dictionary from file"""
- from models.base_model import BaseModel
- from models.user import User
- from models.place import Place
- from models.state import State
- from models.city import City
- from models.amenity import Amenity
- from models.review import Review
-
- classes = {
- 'BaseModel': BaseModel, 'User': User, 'Place': Place,
- 'State': State, 'City': City, 'Amenity': Amenity,
- 'Review': Review
- }
+ """serialize the file path to JSON file path
+ """
try:
- temp = {}
- with open(FileStorage.__file_path, 'r') as f:
- temp = json.load(f)
- for key, val in temp.items():
- self.all()[key] = classes[val['__class__']](**val)
+ with open(self.__file_path, 'r', encoding="UTF-8") as f:
+ for key, value in (json.load(f)).items():
+ value = eval(value["__class__"])(**value)
+ self.__objects[key] = value
except FileNotFoundError:
pass
+
+ def delete(self, obj=None):
+ """ delete an existing element
+ """
+ if obj:
+ key = "{}.{}".format(type(obj).__name__, obj.id)
+ del self.__objects[key]
+
+ def close(self):
+ """ calls reload()
+ """
+ self.reload()
diff --git a/models/place.py b/models/place.py
old mode 100644
new mode 100755
index 5221e8210d17..1b795adda7c5
--- a/models/place.py
+++ b/models/place.py
@@ -1,18 +1,83 @@
#!/usr/bin/python3
-""" Place Module for HBNB project """
-from models.base_model import BaseModel
-
-
-class Place(BaseModel):
- """ A place to stay """
- city_id = ""
- user_id = ""
- name = ""
- description = ""
- number_rooms = 0
- number_bathrooms = 0
- max_guest = 0
- price_by_night = 0
- latitude = 0.0
- longitude = 0.0
+"""This is the place class"""
+from sqlalchemy.ext.declarative import declarative_base
+from models.base_model import BaseModel, Base
+from sqlalchemy import Column, Table, String, Integer, Float, ForeignKey
+from sqlalchemy.orm import relationship
+from os import getenv
+import models
+
+
+place_amenity = Table("place_amenity", Base.metadata,
+ Column("place_id", String(60),
+ ForeignKey("places.id"),
+ primary_key=True,
+ nullable=False),
+ Column("amenity_id", String(60),
+ ForeignKey("amenities.id"),
+ primary_key=True,
+ nullable=False))
+
+
+class Place(BaseModel, Base):
+ """This is the class for Place
+ Attributes:
+ city_id: city id
+ user_id: user id
+ name: name input
+ description: string of description
+ number_rooms: number of room in int
+ number_bathrooms: number of bathrooms in int
+ max_guest: maximum guest in int
+ price_by_night:: pice for a staying in int
+ latitude: latitude in flaot
+ longitude: longitude in float
+ amenity_ids: list of Amenity ids
+ """
+ __tablename__ = "places"
+ city_id = Column(String(60), ForeignKey("cities.id"), nullable=False)
+ user_id = Column(String(60), ForeignKey("users.id"), nullable=False)
+ name = Column(String(128), nullable=False)
+ description = Column(String(1024))
+ number_rooms = Column(Integer, nullable=False, default=0)
+ number_bathrooms = Column(Integer, nullable=False, default=0)
+ max_guest = Column(Integer, nullable=False, default=0)
+ price_by_night = Column(Integer, nullable=False, default=0)
+ latitude = Column(Float)
+ longitude = Column(Float)
amenity_ids = []
+
+ if getenv("HBNB_TYPE_STORAGE") == "db":
+ reviews = relationship("Review", cascade='all, delete, delete-orphan',
+ backref="place")
+
+ amenities = relationship("Amenity", secondary=place_amenity,
+ viewonly=False,
+ back_populates="place_amenities")
+ else:
+ @property
+ def reviews(self):
+ """ Returns list of reviews.id """
+ var = models.storage.all()
+ lista = []
+ result = []
+ for key in var:
+ review = key.replace('.', ' ')
+ review = shlex.split(review)
+ if (review[0] == 'Review'):
+ lista.append(var[key])
+ for elem in lista:
+ if (elem.place_id == self.id):
+ result.append(elem)
+ return (result)
+
+ @property
+ def amenities(self):
+ """ Returns list of amenity ids """
+ return self.amenity_ids
+
+ @amenities.setter
+ def amenities(self, obj=None):
+ """ Appends amenity ids to the attribute """
+ if type(obj) is Amenity and obj.id not in self.amenity_ids:
+ self.amenity_ids.append(obj.id)
diff --git a/models/review.py b/models/review.py
old mode 100644
new mode 100755
index c487d90d34f0..3fcebb30bc26
--- a/models/review.py
+++ b/models/review.py
@@ -1,10 +1,18 @@
#!/usr/bin/python3
-""" Review module for the HBNB project """
-from models.base_model import BaseModel
+"""This is the review class"""
+from sqlalchemy.ext.declarative import declarative_base
+from models.base_model import BaseModel, Base
+from sqlalchemy import Column, Integer, String, ForeignKey, Float
-class Review(BaseModel):
- """ Review classto store review information """
- place_id = ""
- user_id = ""
- text = ""
+class Review(BaseModel, Base):
+ """This is the class for Review
+ Attributes:
+ place_id: place id
+ user_id: user id
+ text: review description
+ """
+ __tablename__ = "reviews"
+ text = Column(String(1024), nullable=False)
+ place_id = Column(String(60), ForeignKey("places.id"), nullable=False)
+ user_id = Column(String(60), ForeignKey("users.id"), nullable=False)
diff --git a/models/state.py b/models/state.py
old mode 100644
new mode 100755
index 583f041f07e4..250e66a82f14
--- a/models/state.py
+++ b/models/state.py
@@ -1,8 +1,35 @@
#!/usr/bin/python3
-""" State Module for HBNB project """
-from models.base_model import BaseModel
+"""This is the state class"""
+from sqlalchemy.ext.declarative import declarative_base
+from models.base_model import BaseModel, Base
+from sqlalchemy.orm import relationship
+from sqlalchemy import Column, Integer, String
+import models
+from models.city import City
+import shlex
-class State(BaseModel):
- """ State class """
- name = ""
+class State(BaseModel, Base):
+ """This is the class for State
+ Attributes:
+ name: input name
+ """
+ __tablename__ = "states"
+ name = Column(String(128), nullable=False)
+ cities = relationship("City", cascade='all, delete, delete-orphan',
+ backref="state")
+
+ @property
+ def cities(self):
+ var = models.storage.all()
+ lista = []
+ result = []
+ for key in var:
+ city = key.replace('.', ' ')
+ city = shlex.split(city)
+ if (city[0] == 'City'):
+ lista.append(var[key])
+ for elem in lista:
+ if (elem.state_id == self.id):
+ result.append(elem)
+ return (result)
diff --git a/models/states.py b/models/states.py
new file mode 100755
index 000000000000..e69de29bb2d1
diff --git a/models/user.py b/models/user.py
old mode 100644
new mode 100755
index 4b54a6d24120..d15bdfbecffb
--- a/models/user.py
+++ b/models/user.py
@@ -1,11 +1,27 @@
#!/usr/bin/python3
-"""This module defines a class User"""
-from models.base_model import BaseModel
+"""This is the user class"""
+from sqlalchemy.ext.declarative import declarative_base
+from models.base_model import BaseModel, Base
+from sqlalchemy import Column, Integer, String
+from sqlalchemy.orm import relationship
+from models.place import Place
+from models.review import Review
-class User(BaseModel):
- """This class defines a user by various attributes"""
- email = ''
- password = ''
- first_name = ''
- last_name = ''
+class User(BaseModel, Base):
+ """This is the class for user
+ Attributes:
+ email: email address
+ password: password for you login
+ first_name: first name
+ last_name: last name
+ """
+ __tablename__ = "users"
+ email = Column(String(128), nullable=False)
+ password = Column(String(128), nullable=False)
+ first_name = Column(String(128))
+ last_name = Column(String(128))
+ places = relationship("Place", cascade='all, delete, delete-orphan',
+ backref="user")
+ reviews = relationship("Review", cascade='all, delete, delete-orphan',
+ backref="user")
diff --git a/setup_mysql_dev.sql b/setup_mysql_dev.sql
new file mode 100644
index 000000000000..1453a7a6432c
--- /dev/null
+++ b/setup_mysql_dev.sql
@@ -0,0 +1,20 @@
+-- Creates a MySQL server with:
+-- Database hbnb_dev_db.
+-- User hbnb_dev with password hbnb_dev_pwd in localhost.
+-- Grants all privileges for hbnb_dev on hbnb_dev_db.
+-- Grants SELECT privilege for hbnb_dev on performance.
+
+-- Create the database if it doesn't exist
+CREATE DATABASE IF NOT EXISTS hbnb_dev_db;
+
+-- Create the user if it doesn't exist
+CREATE USER IF NOT EXISTS 'hbnb_dev'@'localhost' IDENTIFIED BY 'hbnb_dev_pwd';
+
+-- Grant all privileges on hbnb_dev_db to hbnb_dev
+GRANT ALL PRIVILEGES ON hbnb_dev_db.* TO 'hbnb_dev'@'localhost';
+
+-- Grant SELECT privilege on performance_schema to hbnb_dev
+GRANT SELECT ON performance_schema.* TO 'hbnb_dev'@'localhost';
+
+-- Flush privileges to apply changes
+FLUSH PRIVILEGES;
diff --git a/setup_mysql_test.sql b/setup_mysql_test.sql
new file mode 100644
index 000000000000..922e9ae8cfb1
--- /dev/null
+++ b/setup_mysql_test.sql
@@ -0,0 +1,21 @@
+-- Creates a MySQL server with:
+-- Database hbnb_test_db.
+-- User hbnb_test with password hbnb_test_pwd in localhost.
+-- Grants all privileges for hbnb_test on hbnb_test_db.
+-- Grants SELECT privilege for hbnb_test on performance_schema.
+
+
+-- Create the database if it doesn't exist
+CREATE DATABASE IF NOT EXISTS hbnb_test_db;
+
+-- Create the user if it doesn't exist
+CREATE USER IF NOT EXISTS 'hbnb_test'@'localhost' IDENTIFIED BY 'hbnb_test_pwd';
+
+-- Grant all privileges on hbnb_test_db to hbnb_test
+GRANT ALL PRIVILEGES ON hbnb_test_db.* TO 'hbnb_test'@'localhost';
+
+-- Grant SELECT privilege on performance_schema to hbnb_test
+GRANT SELECT ON performance_schema.* TO 'hbnb_test'@'localhost';
+
+-- Flush privileges to apply changes
+FLUSH PRIVILEGES;
diff --git a/tests/test_console.py b/tests/test_console.py
new file mode 100644
index 000000000000..015e5c46886a
--- /dev/null
+++ b/tests/test_console.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python3
+"""
+Contains the class TestConsoleDocs
+"""
+
+import console
+import inspect
+import pep8
+import unittest
+HBNBCommand = console.HBNBCommand
+
+
+class TestConsoleDocs(unittest.TestCase):
+ """Class for testing documentation of the console"""
+ def test_pep8_conformance_console(self):
+ """Test that console.py conforms to PEP8."""
+ pep8s = pep8.StyleGuide(quiet=True)
+ result = pep8s.check_files(['console.py'])
+ self.assertEqual(result.total_errors, 0,
+ "Found code style errors (and warnings).")
+
+ def test_pep8_conformance_test_console(self):
+ """Test that tests/test_console.py conforms to PEP8."""
+ pep8s = pep8.StyleGuide(quiet=True)
+ result = pep8s.check_files(['tests/test_console.py'])
+ self.assertEqual(result.total_errors, 0,
+ "Found code style errors (and warnings).")
+
+ def test_console_module_docstring(self):
+ """Test for the console.py module docstring"""
+ self.assertIsNot(console.__doc__, None,
+ "console.py needs a docstring")
+ self.assertTrue(len(console.__doc__) >= 1,
+ "console.py needs a docstring")
+
+ def test_HBNBCommand_class_docstring(self):
+ """Test for the HBNBCommand class docstring"""
+ self.assertIsNot(HBNBCommand.__doc__, None,
+ "HBNBCommand class needs a docstring")
+ self.assertTrue(len(HBNBCommand.__doc__) >= 1,
+ "HBNBCommand class needs a docstring")
diff --git a/tests/test_models/test_amenity.py b/tests/test_models/test_amenity.py
index e47ab0d2e09a..6286b774aab3 100755
--- a/tests/test_models/test_amenity.py
+++ b/tests/test_models/test_amenity.py
@@ -1,11 +1,11 @@
#!/usr/bin/python3
""" """
-from tests.test_models.test_base_model import test_basemodel
+from tests.test_models.test_base_model import TestBaseModel
from models.amenity import Amenity
-class test_Amenity(test_basemodel):
- """ """
+class TestAmenity(TestBaseModel):
+ """ Test for amenity"""
def __init__(self, *args, **kwargs):
""" """
@@ -16,4 +16,5 @@ def __init__(self, *args, **kwargs):
def test_name2(self):
""" """
new = self.value()
+ new.name = "amenity"
self.assertEqual(type(new.name), str)
diff --git a/tests/test_models/test_base_model.py b/tests/test_models/test_base_model.py
index b6fef535c595..468ea36dc1ab 100755
--- a/tests/test_models/test_base_model.py
+++ b/tests/test_models/test_base_model.py
@@ -8,8 +8,8 @@
import os
-class test_basemodel(unittest.TestCase):
- """ """
+class TestBaseModel(unittest.TestCase):
+ """ Test base model"""
def __init__(self, *args, **kwargs):
""" """
@@ -47,21 +47,6 @@ def test_kwargs_int(self):
with self.assertRaises(TypeError):
new = BaseModel(**copy)
- def test_save(self):
- """ Testing save """
- i = self.value()
- i.save()
- key = self.name + "." + i.id
- with open('file.json', 'r') as f:
- j = json.load(f)
- self.assertEqual(j[key], i.to_dict())
-
- def test_str(self):
- """ """
- i = self.value()
- self.assertEqual(str(i), '[{}] ({}) {}'.format(self.name, i.id,
- i.__dict__))
-
def test_todict(self):
""" """
i = self.value()
@@ -74,12 +59,6 @@ def test_kwargs_none(self):
with self.assertRaises(TypeError):
new = self.value(**n)
- def test_kwargs_one(self):
- """ """
- n = {'Name': 'test'}
- with self.assertRaises(KeyError):
- new = self.value(**n)
-
def test_id(self):
""" """
new = self.value()
@@ -96,4 +75,5 @@ def test_updated_at(self):
self.assertEqual(type(new.updated_at), datetime.datetime)
n = new.to_dict()
new = BaseModel(**n)
- self.assertFalse(new.created_at == new.updated_at)
+ self.assertAlmostEqual(new.created_at.timestamp(),
+ new.updated_at.timestamp(), delta=1)
diff --git a/tests/test_models/test_city.py b/tests/test_models/test_city.py
index 2673225808c0..394842db5d91 100755
--- a/tests/test_models/test_city.py
+++ b/tests/test_models/test_city.py
@@ -1,11 +1,12 @@
#!/usr/bin/python3
""" """
-from tests.test_models.test_base_model import test_basemodel
+from models.state import State
+from tests.test_models.test_base_model import TestBaseModel
from models.city import City
-class test_City(test_basemodel):
- """ """
+class TestCity(TestBaseModel):
+ """ Test for city"""
def __init__(self, *args, **kwargs):
""" """
@@ -15,10 +16,13 @@ def __init__(self, *args, **kwargs):
def test_state_id(self):
""" """
+ state = State()
new = self.value()
+ new.state_id = state.id
self.assertEqual(type(new.state_id), str)
def test_name(self):
""" """
new = self.value()
+ new.name = "Batch"
self.assertEqual(type(new.name), str)
diff --git a/tests/test_models/test_engine/test_db_storage.py b/tests/test_models/test_engine/test_db_storage.py
new file mode 100755
index 000000000000..7d5c38cee4bc
--- /dev/null
+++ b/tests/test_models/test_engine/test_db_storage.py
@@ -0,0 +1,103 @@
+#!/usr/bin/python3
+import unittest
+import models
+from models.user import User
+from models.review import Review
+from models.amenity import Amenity
+from models.state import State
+from models.place import Place
+from models.city import City
+import os
+
+
+# skip these test if the storage is not db
+@unittest.skipIf(os.getenv('HBNB_TYPE_STORAGE') != 'db', "skip if not fs")
+class TestDBStorage(unittest.TestCase):
+ """DB Storage test"""
+
+ def setUp(self):
+ """ Set up test environment """
+ self.storage = models.storage
+
+ def tearDown(self):
+ """ Remove storage file at end of tests """
+ del self.storage
+
+ def test_user(self):
+ """ Tests user """
+ user = User(name="Chyna", email="chyna@gmail.com", password="Chyna12345")
+ user.save()
+ self.assertFalse(user.id in self.storage.all())
+ self.assertEqual(user.name, "Chyna")
+
+ def test_city(self):
+ """ test city """
+ state = State(name="California")
+ state.save()
+ city = City(name="Batch")
+ city.state_id = state.id
+ city.save()
+ self.assertFalse(city.id in self.storage.all())
+ self.assertEqual(city.name, "Batch")
+
+ def test_state(self):
+ """ test state"""
+ state = State(name="California")
+ state.save()
+ self.assertFalse(state.id in self.storage.all())
+ self.assertEqual(state.name, "California")
+
+ def test_place(self):
+ """Test place"""
+ state = State(name="California")
+ state.save()
+
+ city = City(name="Batch")
+ city.state_id = state.id
+ city.save()
+
+ user = User(name="Chyna", email="chyna@gmail.com", password="Chyna12345")
+ user.save()
+
+ place = Place(name="Palace", number_rooms=4)
+ place.city_id = city.id
+ place.user_id = user.id
+ place.save()
+
+ self.assertFalse(place.id in self.storage.all())
+ self.assertEqual(place.number_rooms, 4)
+ self.assertEqual(place.name, "Palace")
+
+ def test_amenity(self):
+ """ test amenity """
+ amenity = Amenity(name="Startlink")
+ amenity.save()
+ self.assertFalse(amenity.id in self.storage.all())
+ self.assertTrue(amenity.name, "Startlink")
+
+ def test_review(self):
+ """ test review """
+ state = State(name="California")
+ state.save()
+
+ city = City(name="Batch")
+ city.state_id = state.id
+ city.save()
+
+ user = User(name="Chyna", email="chyna@gmail.com", password="Chyna12345")
+ user.save()
+
+ place = Place(name="Palace", number_rooms=4)
+ place.city_id = city.id
+ place.user_id = user.id
+ place.save()
+
+ review = Review(text="no comment", place_id=place.id, user_id=user.id)
+ review.save()
+
+ self.assertFalse(review.id in self.storage.all())
+ self.assertEqual(review.text, "no comment")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/test_models/test_engine/test_file_storage.py b/tests/test_models/test_engine/test_file_storage.py
index e1de7198b697..9132134cc7ac 100755
--- a/tests/test_models/test_engine/test_file_storage.py
+++ b/tests/test_models/test_engine/test_file_storage.py
@@ -1,21 +1,24 @@
#!/usr/bin/python3
""" Module for testing file storage"""
import unittest
+
+import models
from models.base_model import BaseModel
-from models import storage
import os
-class test_fileStorage(unittest.TestCase):
+@unittest.skipIf(os.getenv('HBNB_TYPE_STORAGE') == 'db', "skip if not db")
+class TestFileStorage(unittest.TestCase):
""" Class to test the file storage method """
def setUp(self):
""" Set up test environment """
+ self.storage = models.storage
del_list = []
- for key in storage._FileStorage__objects.keys():
+ for key in self.storage._FileStorage__objects.keys():
del_list.append(key)
for key in del_list:
- del storage._FileStorage__objects[key]
+ del self.storage._FileStorage__objects[key]
def tearDown(self):
""" Remove storage file at end of tests """
@@ -24,21 +27,23 @@ def tearDown(self):
except:
pass
+ del self.storage
+
def test_obj_list_empty(self):
""" __objects is initially empty """
- self.assertEqual(len(storage.all()), 0)
+ self.assertEqual(len(self.storage.all()), 0)
def test_new(self):
""" New object is correctly added to __objects """
new = BaseModel()
- for obj in storage.all().values():
+ for obj in self.storage.all().values():
temp = obj
- self.assertTrue(temp is obj)
+ self.assertTrue(temp is obj)
def test_all(self):
""" __objects is properly returned """
new = BaseModel()
- temp = storage.all()
+ temp = self.storage.all()
self.assertIsInstance(temp, dict)
def test_base_model_instantiation(self):
@@ -57,28 +62,28 @@ def test_empty(self):
def test_save(self):
""" FileStorage save method """
new = BaseModel()
- storage.save()
+ self.storage.save()
self.assertTrue(os.path.exists('file.json'))
def test_reload(self):
""" Storage file is successfully loaded to __objects """
new = BaseModel()
- storage.save()
- storage.reload()
- for obj in storage.all().values():
+ self.storage.save()
+ self.storage.reload()
+ for obj in self.storage.all().values():
loaded = obj
- self.assertEqual(new.to_dict()['id'], loaded.to_dict()['id'])
+ self.assertEqual(new.to_dict()['id'], loaded.to_dict()['id'])
def test_reload_empty(self):
""" Load from an empty file """
with open('file.json', 'w') as f:
pass
with self.assertRaises(ValueError):
- storage.reload()
+ self.storage.reload()
def test_reload_from_nonexistent(self):
""" Nothing happens if file does not exist """
- self.assertEqual(storage.reload(), None)
+ self.assertEqual(self.storage.reload(), None)
def test_base_model_save(self):
""" BaseModel save method calls storage save """
@@ -88,22 +93,22 @@ def test_base_model_save(self):
def test_type_path(self):
""" Confirm __file_path is string """
- self.assertEqual(type(storage._FileStorage__file_path), str)
+ self.assertEqual(type(self.storage._FileStorage__file_path), str)
def test_type_objects(self):
""" Confirm __objects is a dict """
- self.assertEqual(type(storage.all()), dict)
+ self.assertEqual(type(self.storage.all()), dict)
def test_key_format(self):
""" Key is properly formatted """
new = BaseModel()
_id = new.to_dict()['id']
- for key in storage.all().keys():
+ for key in self.storage.all().keys():
temp = key
- self.assertEqual(temp, 'BaseModel' + '.' + _id)
+ self.assertEqual(temp, 'BaseModel' + '.' + _id)
def test_storage_var_created(self):
""" FileStorage object storage created """
from models.engine.file_storage import FileStorage
- print(type(storage))
- self.assertEqual(type(storage), FileStorage)
+ print(type(self.storage))
+ self.assertEqual(type(self.storage), FileStorage)
diff --git a/tests/test_models/test_place.py b/tests/test_models/test_place.py
index ec133d104ef5..1f7a7fcc1f87 100755
--- a/tests/test_models/test_place.py
+++ b/tests/test_models/test_place.py
@@ -1,11 +1,13 @@
#!/usr/bin/python3
""" """
-from tests.test_models.test_base_model import test_basemodel
+from models.city import City
+from models.user import User
+from tests.test_models.test_base_model import TestBaseModel
from models.place import Place
-class test_Place(test_basemodel):
- """ """
+class TestPlace(TestBaseModel):
+ """ Test for place"""
def __init__(self, *args, **kwargs):
""" """
@@ -16,52 +18,64 @@ def __init__(self, *args, **kwargs):
def test_city_id(self):
""" """
new = self.value()
+ city = City()
+ new.city_id = city.id
self.assertEqual(type(new.city_id), str)
def test_user_id(self):
""" """
new = self.value()
+ user = User()
+ new.user_id = user.id
self.assertEqual(type(new.user_id), str)
def test_name(self):
""" """
new = self.value()
+ new.name = "Place"
self.assertEqual(type(new.name), str)
def test_description(self):
""" """
new = self.value()
+ new.description = ""
self.assertEqual(type(new.description), str)
def test_number_rooms(self):
""" """
new = self.value()
+ new.number_rooms = 4
self.assertEqual(type(new.number_rooms), int)
def test_number_bathrooms(self):
""" """
new = self.value()
+ new.number_bathrooms = 2
self.assertEqual(type(new.number_bathrooms), int)
def test_max_guest(self):
""" """
new = self.value()
+ new.max_guest = 8
self.assertEqual(type(new.max_guest), int)
def test_price_by_night(self):
""" """
new = self.value()
+ new.price_by_night = 18
self.assertEqual(type(new.price_by_night), int)
def test_latitude(self):
""" """
new = self.value()
+ new.latitude = -123.085222
self.assertEqual(type(new.latitude), float)
def test_longitude(self):
""" """
new = self.value()
- self.assertEqual(type(new.latitude), float)
+ new.longitude = -120.085222
+ self.assertEqual(type(new.longitude), float)
def test_amenity_ids(self):
""" """
diff --git a/tests/test_models/test_review.py b/tests/test_models/test_review.py
index 23fbc61529e8..6804c485d917 100755
--- a/tests/test_models/test_review.py
+++ b/tests/test_models/test_review.py
@@ -1,11 +1,13 @@
#!/usr/bin/python3
""" """
-from tests.test_models.test_base_model import test_basemodel
+from models.place import Place
+from models.user import User
+from tests.test_models.test_base_model import TestBaseModel
from models.review import Review
-class test_review(test_basemodel):
- """ """
+class TestReview(TestBaseModel):
+ """Test for review """
def __init__(self, *args, **kwargs):
""" """
@@ -16,14 +18,19 @@ def __init__(self, *args, **kwargs):
def test_place_id(self):
""" """
new = self.value()
+ place = Place()
+ new.place_id = place.id
self.assertEqual(type(new.place_id), str)
def test_user_id(self):
""" """
new = self.value()
+ user = User()
+ new.user_id = user.id
self.assertEqual(type(new.user_id), str)
def test_text(self):
""" """
new = self.value()
+ new.text = ""
self.assertEqual(type(new.text), str)
diff --git a/tests/test_models/test_state.py b/tests/test_models/test_state.py
index 719e096d8633..7149c879f7aa 100755
--- a/tests/test_models/test_state.py
+++ b/tests/test_models/test_state.py
@@ -1,19 +1,20 @@
#!/usr/bin/python3
""" """
-from tests.test_models.test_base_model import test_basemodel
+from tests.test_models.test_base_model import TestBaseModel
from models.state import State
-class test_state(test_basemodel):
- """ """
+class TestState(TestBaseModel):
+ """Test for state """
def __init__(self, *args, **kwargs):
""" """
super().__init__(*args, **kwargs)
- self.name = "State"
+ self.name = "California"
self.value = State
def test_name3(self):
""" """
new = self.value()
+ new.name = "Arizona"
self.assertEqual(type(new.name), str)
diff --git a/tests/test_models/test_user.py b/tests/test_models/test_user.py
index 8660300f8bbc..c26f6956dd12 100755
--- a/tests/test_models/test_user.py
+++ b/tests/test_models/test_user.py
@@ -1,11 +1,11 @@
#!/usr/bin/python3
""" """
-from tests.test_models.test_base_model import test_basemodel
+from tests.test_models.test_base_model import TestBaseModel
from models.user import User
-class test_User(test_basemodel):
- """ """
+class TestUser(TestBaseModel):
+ """ Test for user"""
def __init__(self, *args, **kwargs):
""" """
@@ -16,19 +16,23 @@ def __init__(self, *args, **kwargs):
def test_first_name(self):
""" """
new = self.value()
+ new.first_name = "Chyna"
self.assertEqual(type(new.first_name), str)
def test_last_name(self):
""" """
new = self.value()
+ new.last_name = "Chyna"
self.assertEqual(type(new.last_name), str)
def test_email(self):
""" """
new = self.value()
+ new.email = "angoyewally@gmail.com"
self.assertEqual(type(new.email), str)
def test_password(self):
""" """
new = self.value()
+ new.password = "123aashja"
self.assertEqual(type(new.password), str)