Skip to content

edafeoke/AirBnB_clone

Repository files navigation

AirBnB_clone - The Console

logo

A command interpreter to manipulate data without a visual interface (perfect for development and debugging)

project_image

Installation

git clone https://github.com/edafeoke/AirBnB_clone.git
cd AirBnB_clone

Usage

Execution

It works in interactive mode

./console.py
(hbnb) help

Documented commands (type help <topic>):
========================================
EOF  help  quit create show destroy all update

It also works in non-interactive mode

$ echo "help" | ./console.py
(hbnb)

Documented commands (type help <topic>):
========================================
EOF  help  quit create show destroy all update
(hbnb) 
$
$ cat test_help
help
$
$ cat test_help | ./console.py
(hbnb)

Documented commands (type help <topic>):
========================================
EOF  help  quit create show destroy all update
(hbnb) 
$

Console commands

EOF
Quits the console
(hbnb) EOF
quit
Quits the console
(hbnb) quit
help
Show help text
(hbnb) help
Documented commands (type help <topic>):
    ========================================
    EOF  help  quit create show destroy all update

(hbnb) help quit
(hbnb) Quits the console
create
Creates a new instance of BaseModel, saves it (to the JSON file) and prints the id
(hbnb) create BaseModel
49faff9a-6318-451f-87b6-910505c55907
(hbnb)

This project consists of eleven (11) mandatory tasks and seven (7) tasks. Each task is linked and will help to:

  1. Put in place a parent class (called BaseModel) to take care of the initialization, serialization and deserialization of your future instances
  2. Create a simple flow of serialization/deserialization: Instance <-> Dictionary <-> JSON string <-> file.
  3. Create all classes used for AirBnB (User, State, City, Place…) that inherit from BaseModel,
  4. Create the first abstracted storage engine of the project: File storage.
  5. Create all unittests to validate all our classes and storage engine.

#First step:

Write a command interpreter to manage your AirBnB objects. This command line interpreter would b limited to specific use-case which includes:

  1. Creating a new object (ex: a new User or a new Place)
  2. Retrieving an object from a file, a database etc…
  3. Peforming operations on objects (count, compute stats, etc…)
  4. Updating attributes of an object
  5. Destroying an object

#REQUIREMENTS

#For python scripts:

  1. Allowed editors: vi, vim, emacs 2.All your files will be interpreted/compiled on Ubuntu 20.04 LTS using python3 (version 3.8.5)
  2. All your files should end with a new line
  3. The first line of all your files should be exactly #!/usr/bin/python3
  4. A README.md file, at the root of the folder of the project, is mandatory
  5. Your code should use the pycodestyle (version 2.7.*)
  6. All your files must be executable
  7. The length of your files will be tested using wc
  8. All your modules should have a documentation (python3 -c 'print(import("my_module").doc)')
  9. All your classes should have a documentation (python3 -c 'print(import("my_module").MyClass.doc)')
  10. All your functions (inside and outside a class) should have a documentation (python3 -c 'print(import("my_module").my_function.doc)' and python3 -c 'print(import("my_module").MyClass.my_function.doc)')

#Note: 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).

#For Python Unit Tests:

  1. Allowed editors: vi, vim, emacs

  2. All your files should end with a new line

  3. All your test files should be inside a folder tests

  4. You have to use the unittest module

  5. All your test files should be python files (extension: .py)

  6. All your test files and folders should start by test_

  7. Your file organization in the tests folder should be the same as your project. e.g., For models/base_model.py, unit tests must be in: tests/test_models/test_base_model.py e.g., For models/user.py, unit tests must be in: tests/test_models/test_user.py

  8. All your tests should be executed by using this command: python3 -m unittest discover tests

  9. You can also test file by file by using this command: python3 -m unittest tests/test_models/test_base_model.py

  10. All your modules should have a documentation (python3 -c 'print(import("my_module").doc)').

  11. All your classes should have a documentation (python3 -c 'print(import("my_module").MyClass.doc)').

  12. All your functions (inside and outside a class) should have a documentation (python3 -c 'print(import("my_module").my_function.doc)' and python3 -c 'print(import("my_module").MyClass.my_function.doc)')

NOTE: All tests should also pass in non-interactive mode: $ echo "python3 -m unittest discover tests" | bash

MANDATORY TASKS

Task 0. README, AUTHORS

Write a README.md containing: a. Description of the project b. Description of the command interpreter: C. How to start it D. How to use it

You should have an AUTHORS file at the root of your repository, listing all individuals having contributed content to the repository. For format, reference Docker’s AUTHORS page.

You should use branches and pull requests on GitHub - it will help you as team to organize your work.

#Task 1. Be PEP8 compliant!

Write beautiful code that passes the PEP8 checks.

#Task 2. Unittests

All your files, classes, functions must be tested with unit tests. Unit tests must also pass in non-interactive mode.

#Task 3. BaseModel

Write a class BaseModel that defines all common attributes/methods for other classes:

#models/base_model.py

#Public instance attributes: id: string - assign with an uuid when an instance is created:

you can use uuid.uuid4() to generate unique id but don’t forget to convert to a string

the goal is to have unique id for each BaseModel

created_at: datetime - assign with the current datetime when an instance is created

updated_at: datetime - assign with the current datetime when an instance is created and it will be updated every time you change your object

str: should print: [] (<self.id>) <self.dict>

#Public instance methods:

save(self): updates the public instance attribute updated_at with the current datetime

to_dict(self): returns a dictionary containing all keys/values of dict of the instance:

by using self.dict, only instance attributes set will be returned

a key class must be added to this dictionary with the class name of the object

created_at and updated_at must be converted to string object in ISO format:

format: %Y-%m-%dT%H:%M:%S.%f (ex: 2017-06-14T22:31:03.285259)

you can use isoformat() of datetime object

This method will be the first piece of the serialization/deserialization process: create a dictionary representation with “simple object type” of our BaseModel

#Task 4. Create BaseModel from dictionary

Previously we created a method to generate a dictionary representation of an instance (method to_dict()).

Now it’s time to re-create an instance with this dictionary representation.

<class 'BaseModel'> -> to_dict() -> <class 'dict'> -> <class 'BaseModel'> Update models/base_model.py:

init(self, *args, **kwargs):

you will use *args, **kwargs arguments for the constructor of a BaseModel. (more information inside the AirBnB clone concept page) *args won’t be used

if kwargs is not empty:

Each key of this dictionary is an attribute name (Note class from kwargs is the only one that should not be added as an attribute. See the example output, below). Each value of this dictionary is the value of this attribute name.

Warning: 'created_at' and 'updated_at' are strings in this dictionary, but inside your BaseModel instance is working with datetime object. You have to convert these strings into datetime object. Tip: you know the string format of these datetime.

Otherwise: Create id and created_at as you did previously (new instance).

#Task 5. Store first object

Now we can recreate a BaseModel from another one by using a dictionary representation:

<class 'BaseModel'> -> to_dict() -> <class 'dict'> -> <class 'BaseModel'>

It’s great but it’s still not persistent: Every time you launch the program, you don’t restore all objects created before… The first way you will see here is to save these objects to a file.

Writing the dictionary representation to a file won’t be relevant:

Python doesn’t know how to convert a string to a dictionary (easily)as it’s not human readable. Using this file with another program in Python or other language will be hard.So, you will convert the dictionary representation to a JSON string. JSON is a standard representation of a data structure. With this format, humans can read and all programming languages have a JSON reader and writer.

The flow of serialization-deserialization will be:

#<class 'BaseModel'> -> to_dict() -> <class 'dict'> -> JSON dump -> <class 'str'> -> FILE -> <class 'str'> -> JSON load -> <class 'dict'> -> <class 'BaseModel'>

#Terms:

Simple Python data structure: Dictionaries, arrays, number and string. ex: { '12': { 'numbers': [1, 2, 3], 'name': "John" } }

JSON string representation: String representing a simple data structure in JSON format. ex: '{ "12": { "numbers": [1, 2, 3], "name": "John" } }'

Write a class FileStorage that serializes instances to a JSON file and deserializes JSON file to instances:

models/engine/file_storage.py

#Private class attributes:

__file_path: string - path to the JSON file (ex: file.json)

__objects: dictionary - empty but will store all objects by .id (ex: to store a BaseModel object with id=12121212, the key will be BaseModel.12121212)

#Public instance methods:

all(self): returns the dictionary __objects

new(self, obj): sets in __objects the obj with key .id

save(self): serializes __objects to the JSON file (path: __file_path)

reload(self): deserializes the JSON file to _objects (only if the JSON file (

_file_path) exists ; otherwise, do nothing. If the file doesn’t exist, no exception should be raised)

Update models/init.py: to create a unique FileStorage instance for your application.

import file_storage.py

Create the variable storage, an instance of FileStorage.

Call reload() method on this variable.

Update models/base_model.py: to link your BaseModel to FileStorage by using the variable storage.

Import the variable storage

in the method save(self): Call save(self) method of storage

init(self, *args, **kwargs): If it’s a new instance (not from a dictionary representation), add a call to the method new(self) on storage

#Task 6. Console 0.0.1

Write a program called console.py that contains the entry point of the command interpreter:

You must use the module cmd.

Your class definition must be: class HBNBCommand(cmd.Cmd):

Your command interpreter should implement:

-Quit and EOF to exit the program.

-Help (this action is provided by default by cmd but you should keep it updated and documented as you work through tasks)

-a custom prompt: (hbnb).

-An empty line + ENTER shouldn’t execute anything

-Your code should not be executed when imported

Warning:

You should end your file with:

if name == 'main': HBNBCommand().cmdloop()

This is to make your program executable except when imported. Please don’t add anything around - the Checker won’t like it otherwise.

#Task 7. Console 0.1

Update your command interpreter (console.py) to have these commands:

create: Creates a new instance of BaseModel, saves it (to the JSON file) and prints the id. Ex: $ create BaseModel.

If the class name is missing, print ** class name missing ** (ex: $ create).

If the class name doesn’t exist, print ** class doesn't exist ** (ex: $ create MyModel).

show: Prints the string representation of an instance based on the class name and id. Ex: $ show BaseModel 1234-1234-1234.

If the class name is missing, print ** class name missing ** (ex: $ show)

If the class name doesn’t exist, print ** class doesn't exist ** (ex: $ show MyModel)

If the id is missing, print ** instance id missing ** (ex: $ show BaseModel)

If the instance of the class name doesn’t exist for the id, print ** no instance found ** (ex: $ show BaseModel 121212)

destroy: Deletes an instance based on the class name and id (save the change into the JSON file). Ex: $ destroy BaseModel 1234-1234-1234.

If the class name is missing, print ** class name missing ** (ex: $ destroy)

If the class name doesn’t exist, print ** class doesn't exist ** (ex:$ destroy MyModel) If the id is missing, print ** instance id missing ** (ex: $ destroy BaseModel) If the instance of the class name doesn’t exist for the id, print ** no instance found ** (ex: $ destroy BaseModel 121212)

all: Prints all string representation of all instances based or not on the class name. Ex: $ all BaseModel or $ all.

The printed result must be a list of strings.

If the class name doesn’t exist, print ** class doesn't exist ** (ex: $ all MyModel).

update: Updates an instance based on the class name and id by adding or updating attribute (save the change into the JSON file). Ex: $ update BaseModel 1234-1234-1234 email "[email protected]".

Usage: update ""

Only one attribute can be updated at the time.

You can assume the attribute name is valid (exists for this model).

The attribute value must be casted to the attribute type.

If the class name is missing, print ** class name missing ** (ex: $ update).

If the class name doesn’t exist, print ** class doesn't exist ** (ex: $ update MyModel).

If the id is missing, print ** instance id missing ** (ex: $ update BaseModel).

If the instance of the class name doesn’t exist for the id, print ** no instance found ** (ex: $ update BaseModel 121212).

If the attribute name is missing, print ** attribute name missing ** (ex: $ update BaseModel existing-id).

If the value for the attribute name doesn’t exist, print ** value missing ** (ex: $ update BaseModel existing-id first_name).

All other arguments should not be used (Ex: $ update BaseModel 1234-1234-1234 email "[email protected]" first_name "Betty" = $ update BaseModel 1234-1234-1234 email "[email protected]").

id, created_at and updated_at cant’ be updated. You can assume they won’t be passed in the update command. Only “simple” arguments can be updated: string, integer and float. You can assume nobody will try to update list of ids or datetime

Let’s add some rules:

  1. You can assume arguments are always in the right order
  2. Each arguments are separated by a space
  3. A string argument with a space must be between double quote
  4. The error management starts from the first argument to the last one

Note: No unittests needed

#Task 8. First User

Write a class User that inherits from BaseModel:

models/user.py

Public class attributes:

email: string - empty string

password: string - empty string

first_name: string - empty string

last_name: string - empty string

Update FileStorage to manage correctly serialization and deserialization of User.

Update your command interpreter (console.py) to allow show, create, destroy, update and all used with User.

Task 9. More classes!

Write all those classes that inherit from BaseModel:

State (models/state.py):

Public class attributes:

name: string - empty string

City (models/city.py):

Public class attributes:

state_id: string - empty string: it will be the State.id

name: string - empty string

Amenity (models/amenity.py):

Public class attributes:

name: string - empty string

Place (models/place.py):

Public class attributes:

city_id: string - empty string: it will be the City.id

user_id: string - empty string: it will be the User.id

name: string - empty string

description: string - empty string

number_rooms: integer - 0

number_bathrooms: integer - 0

max_guest: integer - 0

price_by_night: integer - 0

latitude: float - 0.0

longitude: float - 0.0

amenity_ids: list of string - empty list: it will be the list of Amenity.id lat er

Review (models/review.py):

Public class attributes:

place_id: string - empty string: it will be the Place.id

user_id: string - empty string: it will be the User.id

text: string - empty string

#Task 10. Console 1.0

Update FileStorage to manage correctly serialization and deserialization of all our new classes: Place, State, City, Amenity and Review

Update your command interpreter (console.py) to allow those actions: show, create, destroy, update and all with all classes created previously.

Enjoy your first console!

No unittests needed for the console

#ADVANCED TASKS.

#Task 11. All instances by class name

Update your command interpreter (console.py) to retrieve all instances of a class by using: .all().

#Task 12. Count instances

Update your command interpreter (console.py) to retrieve the number of instances of a class: .count().

#Task 13. Show

Update your command interpreter (console.py) to retrieve an instance based on its ID: .show().

Errors management must be the same as previously.678 No unittests needed

#Task 14. Destroy

Update your command interpreter (console.py) to destroy an instance based on his ID: .destroy().

Errors management must be the same as previously. No unittests needed

#Task 15. Update

Update your command interpreter (console.py) to update an instance based on his ID: .update(, , ).

Errors management must be the same as previously. No unittests needed

#Task 16. Update from dictionary

Update your command interpreter (console.py) to update an instance based on his ID with a dictionary: .update(, ).

Errors management must be the same as previously.

#Task 17. Unittests for the Console!

Write all unittests for console.py, all features!

For testing the console, you should “intercept” STDOUT of it, we highly recommend you to use:

with patch('sys.stdout', new=StringIO()) as f: HBNBCommand().onecmd("help show")

Otherwise, you will have to re-write the console by replacing precmd by default.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published