From bf10f4181cc4c2ea411482667be41256af353786 Mon Sep 17 00:00:00 2001 From: annadu Date: Wed, 14 Dec 2022 11:52:19 -0800 Subject: [PATCH 01/85] Co-authored-by: CatherineBandarchuk add planet --- app/__init__.py | 5 +++++ app/planets.py | 16 ++++++++++++++++ app/routes.py | 17 ++++++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 app/planets.py diff --git a/app/__init__.py b/app/__init__.py index 70b4cabfe..83fd2ee58 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,7 +1,12 @@ from flask import Flask +from .planets import Planet def create_app(test_config=None): app = Flask(__name__) + from .routes import planets_bp + app.register_blueprint(planets_bp) + return app + diff --git a/app/planets.py b/app/planets.py new file mode 100644 index 000000000..914b1b28d --- /dev/null +++ b/app/planets.py @@ -0,0 +1,16 @@ +class Planet: + def __init__(self, id , name, atmosphere, diameter,description): + self.id = id + self.name = name + self.atmosphere = atmosphere + self.diameter = diameter + self.description = description + +planets_list = [ + Planet("1","Mercury","minimal","0.383","The smallest planet in our solar system and nearest to the Sun, Mercury is only slightly larger than Earth's Moon."), + Planet("2","Venus","CO2, N2","0.949","Venus is the second planet from the Sun and is Earth’s closest planetary neighbor. It’s one of the four inner, terrestrial (or rocky) planets, and it’s often called Earth’s twin because it’s similar in size and density. These are not identical twins, however – there are radical differences between the two worlds."), + Planet("3","Earth","N2, O2, Ar","1.000","Our home planet is the third planet from the Sun, and the only place we know of so far that’s inhabited by living things."), + Planet("4","Mars","CO2, N2, Ar","0.532","Mars is the fourth planet from the Sun – a dusty, cold, desert world with a very thin atmosphere. Mars is also a dynamic planet with seasons, polar ice caps, canyons, extinct volcanoes, and evidence that it was even more active in the past."), + Planet("5","Jupiter","H2, He","11.209","Jupiter has a long history of surprising scientists – all the way back to 1610 when Galileo Galilei found the first moons beyond Earth. That discovery changed the way we see the universe."), + Planet("6","Saturn","H2, He","9.449","Saturn is the sixth planet from the Sun and the second-largest planet in our solar system.") +] \ No newline at end of file diff --git a/app/routes.py b/app/routes.py index 8e9dfe684..9dfff4f8b 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,2 +1,17 @@ -from flask import Blueprint +from flask import Blueprint, jsonify +#from .planets import Planet +import planets +planets_bp = Blueprint("all_planets", __name__, url_prefix = "/planets") +@planets_bp.route("", methods = ["GET"]) +def get_all_planets(): + planets_response = [] + for planet in planets_list: + planets_response.append({ + "id":planet.id, + "name":planet.name, + "atmosphere":planet.atmosphere, + "diameter":planet.diameter, + "description":planet.description + }) + return jsonify(planets_response), 200 \ No newline at end of file From 32b71e625243571d71f5feb053d5cc3a0f8ab910 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Wed, 14 Dec 2022 12:07:56 -0800 Subject: [PATCH 02/85] wave1-worked --- app/__init__.py | 3 +-- app/routes.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 83fd2ee58..632441d02 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,6 +1,5 @@ from flask import Flask -from .planets import Planet - +from .planets import Planet, planets_list def create_app(test_config=None): app = Flask(__name__) diff --git a/app/routes.py b/app/routes.py index 9dfff4f8b..e8d261cac 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,6 +1,6 @@ from flask import Blueprint, jsonify -#from .planets import Planet -import planets +from .planets import Planet, planets_list + planets_bp = Blueprint("all_planets", __name__, url_prefix = "/planets") @planets_bp.route("", methods = ["GET"]) From f1cad19db3dc11945572f7a58b9fdee20fef5a93 Mon Sep 17 00:00:00 2001 From: annadu Date: Wed, 14 Dec 2022 12:09:59 -0800 Subject: [PATCH 03/85] import the planets.py --- app/routes.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/routes.py b/app/routes.py index 9dfff4f8b..f61764e93 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,6 +1,5 @@ from flask import Blueprint, jsonify -#from .planets import Planet -import planets +from .planets import * planets_bp = Blueprint("all_planets", __name__, url_prefix = "/planets") @planets_bp.route("", methods = ["GET"]) From f9c7def89908936b35e9aa9ed15795fc809862f5 Mon Sep 17 00:00:00 2001 From: annadu Date: Thu, 15 Dec 2022 10:58:50 -0800 Subject: [PATCH 04/85] Co-authored-by: CatherineBandarchuk add endpoint by id --- app/planets.py | 23 ++++++++++++++++------- app/routes.py | 31 ++++++++++++++++++++----------- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/app/planets.py b/app/planets.py index 914b1b28d..9b51e4ded 100644 --- a/app/planets.py +++ b/app/planets.py @@ -5,12 +5,21 @@ def __init__(self, id , name, atmosphere, diameter,description): self.atmosphere = atmosphere self.diameter = diameter self.description = description - + + def convert_to_dict(self): + return { + "id":self.id, + "name":self.name, + "atmosphere":self.atmosphere, + "diameter":self.diameter, + "description":self.description + } + planets_list = [ - Planet("1","Mercury","minimal","0.383","The smallest planet in our solar system and nearest to the Sun, Mercury is only slightly larger than Earth's Moon."), - Planet("2","Venus","CO2, N2","0.949","Venus is the second planet from the Sun and is Earth’s closest planetary neighbor. It’s one of the four inner, terrestrial (or rocky) planets, and it’s often called Earth’s twin because it’s similar in size and density. These are not identical twins, however – there are radical differences between the two worlds."), - Planet("3","Earth","N2, O2, Ar","1.000","Our home planet is the third planet from the Sun, and the only place we know of so far that’s inhabited by living things."), - Planet("4","Mars","CO2, N2, Ar","0.532","Mars is the fourth planet from the Sun – a dusty, cold, desert world with a very thin atmosphere. Mars is also a dynamic planet with seasons, polar ice caps, canyons, extinct volcanoes, and evidence that it was even more active in the past."), - Planet("5","Jupiter","H2, He","11.209","Jupiter has a long history of surprising scientists – all the way back to 1610 when Galileo Galilei found the first moons beyond Earth. That discovery changed the way we see the universe."), - Planet("6","Saturn","H2, He","9.449","Saturn is the sixth planet from the Sun and the second-largest planet in our solar system.") + Planet(1,"Mercury","minimal","0.383","The smallest planet in our solar system and nearest to the Sun, Mercury is only slightly larger than Earth's Moon."), + Planet(2,"Venus","CO2, N2","0.949","Venus is the second planet from the Sun and is Earth’s closest planetary neighbor. It’s one of the four inner, terrestrial (or rocky) planets, and it’s often called Earth’s twin because it’s similar in size and density. These are not identical twins, however – there are radical differences between the two worlds."), + Planet(3,"Earth","N2, O2, Ar","1.000","Our home planet is the third planet from the Sun, and the only place we know of so far that’s inhabited by living things."), + Planet(4,"Mars","CO2, N2, Ar","0.532","Mars is the fourth planet from the Sun – a dusty, cold, desert world with a very thin atmosphere. Mars is also a dynamic planet with seasons, polar ice caps, canyons, extinct volcanoes, and evidence that it was even more active in the past."), + Planet(5,"Jupiter","H2, He","11.209","Jupiter has a long history of surprising scientists – all the way back to 1610 when Galileo Galilei found the first moons beyond Earth. That discovery changed the way we see the universe."), + Planet(6,"Saturn","H2, He","9.449","Saturn is the sixth planet from the Sun and the second-largest planet in our solar system.") ] \ No newline at end of file diff --git a/app/routes.py b/app/routes.py index 7889c9904..a1dc39133 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,18 +1,27 @@ -from flask import Blueprint, jsonify +from flask import Blueprint, jsonify, abort, make_response - -from .planets import * +from .planets import Planet, planets_list planets_bp = Blueprint("all_planets", __name__, url_prefix = "/planets") +def validate_planet(planet_id): + try: + planet_id = int(planet_id) + except: + abort(make_response({"massage":f"The planet_id {planet_id} is not valid."}, 400)) + + for planet in planets_list: + if planet.id == planet_id: + return planet + abort(make_response({"massage":f"The planet with id {planet_id} not exist."}, 404)) + @planets_bp.route("", methods = ["GET"]) def get_all_planets(): planets_response = [] for planet in planets_list: - planets_response.append({ - "id":planet.id, - "name":planet.name, - "atmosphere":planet.atmosphere, - "diameter":planet.diameter, - "description":planet.description - }) - return jsonify(planets_response), 200 \ No newline at end of file + planets_response.append(planet.convert_to_dict()) + return jsonify(planets_response), 200 + +@planets_bp.route("/", methods = ["GET"]) +def get_planet_by_id(planet_id): + planet = validate_planet(planet_id) + return jsonify(planet.convert_to_dict(), 200) From e3973043bcc61fb4aaa756ea17e9423791fcd01c Mon Sep 17 00:00:00 2001 From: annadu Date: Thu, 15 Dec 2022 10:59:35 -0800 Subject: [PATCH 05/85] add endpoint --- app/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/__init__.py b/app/__init__.py index 632441d02..02075e69a 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,5 +1,6 @@ from flask import Flask -from .planets import Planet, planets_list + + def create_app(test_config=None): app = Flask(__name__) From 427f3b4e7e2fb53df0086afd92d982099f8670e7 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 15 Dec 2022 11:12:19 -0800 Subject: [PATCH 06/85] My changes --- app/planets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/planets.py b/app/planets.py index 914b1b28d..2e92db73d 100644 --- a/app/planets.py +++ b/app/planets.py @@ -5,7 +5,7 @@ def __init__(self, id , name, atmosphere, diameter,description): self.atmosphere = atmosphere self.diameter = diameter self.description = description - + planets_list = [ Planet("1","Mercury","minimal","0.383","The smallest planet in our solar system and nearest to the Sun, Mercury is only slightly larger than Earth's Moon."), Planet("2","Venus","CO2, N2","0.949","Venus is the second planet from the Sun and is Earth’s closest planetary neighbor. It’s one of the four inner, terrestrial (or rocky) planets, and it’s often called Earth’s twin because it’s similar in size and density. These are not identical twins, however – there are radical differences between the two worlds."), From fd7ec77f01ea784328843a6ed8acdc64ecb966a6 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Tue, 20 Dec 2022 19:38:36 -0800 Subject: [PATCH 07/85] wave_3 complite --- app/__init__.py | 19 ++++++-- app/models/__init__.py | 0 app/models/planet.py | 12 +++++ app/planets.py | 25 ---------- app/routes.py | 27 ----------- app/routes/__init__.py | 0 app/routes/planet_routes.py | 56 ++++++++++++++++++++++ migrations/README | 1 + migrations/alembic.ini | 45 +++++++++++++++++ migrations/env.py | 96 +++++++++++++++++++++++++++++++++++++ migrations/script.py.mako | 24 ++++++++++ 11 files changed, 249 insertions(+), 56 deletions(-) create mode 100644 app/models/__init__.py create mode 100644 app/models/planet.py delete mode 100644 app/planets.py delete mode 100644 app/routes.py create mode 100644 app/routes/__init__.py create mode 100644 app/routes/planet_routes.py create mode 100644 migrations/README create mode 100644 migrations/alembic.ini create mode 100644 migrations/env.py create mode 100644 migrations/script.py.mako diff --git a/app/__init__.py b/app/__init__.py index 491562bba..f861fadf6 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,10 +1,21 @@ from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from flask_migrate import Migrate -def create_app(test_config=None): +db = SQLAlchemy() +migrate = Migrate() + +def create_app(): app = Flask(__name__) - from .routes import planets_bp + app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False + app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql+psycopg2://postgres:postgres@localhost:5432/solar_system_development" + + db.init_app(app) + migrate.init_app(app, db) + + from app.models.planet import Planet + from .routes.planet_routes import planets_bp app.register_blueprint(planets_bp) - return app - + return app \ No newline at end of file diff --git a/app/models/__init__.py b/app/models/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/app/models/planet.py b/app/models/planet.py new file mode 100644 index 000000000..7ce0483a3 --- /dev/null +++ b/app/models/planet.py @@ -0,0 +1,12 @@ +from app import db + +class Planet(db.Model): + id = db.Column(db.Integer, primary_key = True, autoincrement = True) + name = db.Column(db.String, nullable = False) + livable = db.Column(db.Boolean, default = False) + number_of_moons = db.Column(db.Integer, nullable = True) + length_of_year = db.Column(db.Integer, nullable = False) + namesake = db.Column(db.String, nullable = False) + atmosphere = db.Column(db.String, nullable = False) + diameter = db.Column(db.String, nullable = False) + description = db.Column(db.String, nullable = False) \ No newline at end of file diff --git a/app/planets.py b/app/planets.py deleted file mode 100644 index 0e72d5f1f..000000000 --- a/app/planets.py +++ /dev/null @@ -1,25 +0,0 @@ -class Planet: - def __init__(self, id , name, atmosphere, diameter,description): - self.id = id - self.name = name - self.atmosphere = atmosphere - self.diameter = diameter - self.description = description - - def convert_to_dict(self): - return { - "id":self.id, - "name":self.name, - "atmosphere":self.atmosphere, - "diameter":self.diameter, - "description":self.description - } - -planets_list = [ - Planet(1,"Mercury","minimal","0.383","The smallest planet in our solar system and nearest to the Sun, Mercury is only slightly larger than Earth's Moon."), - Planet(2,"Venus","CO2, N2","0.949","Venus is the second planet from the Sun and is Earth’s closest planetary neighbor. It’s one of the four inner, terrestrial (or rocky) planets, and it’s often called Earth’s twin because it’s similar in size and density. These are not identical twins, however – there are radical differences between the two worlds."), - Planet(3,"Earth","N2, O2, Ar","1.000","Our home planet is the third planet from the Sun, and the only place we know of so far that’s inhabited by living things."), - Planet(4,"Mars","CO2, N2, Ar","0.532","Mars is the fourth planet from the Sun – a dusty, cold, desert world with a very thin atmosphere. Mars is also a dynamic planet with seasons, polar ice caps, canyons, extinct volcanoes, and evidence that it was even more active in the past."), - Planet(5,"Jupiter","H2, He","11.209","Jupiter has a long history of surprising scientists – all the way back to 1610 when Galileo Galilei found the first moons beyond Earth. That discovery changed the way we see the universe."), - Planet(6,"Saturn","H2, He","9.449","Saturn is the sixth planet from the Sun and the second-largest planet in our solar system.") -] \ No newline at end of file diff --git a/app/routes.py b/app/routes.py deleted file mode 100644 index a1dc39133..000000000 --- a/app/routes.py +++ /dev/null @@ -1,27 +0,0 @@ -from flask import Blueprint, jsonify, abort, make_response - -from .planets import Planet, planets_list -planets_bp = Blueprint("all_planets", __name__, url_prefix = "/planets") - -def validate_planet(planet_id): - try: - planet_id = int(planet_id) - except: - abort(make_response({"massage":f"The planet_id {planet_id} is not valid."}, 400)) - - for planet in planets_list: - if planet.id == planet_id: - return planet - abort(make_response({"massage":f"The planet with id {planet_id} not exist."}, 404)) - -@planets_bp.route("", methods = ["GET"]) -def get_all_planets(): - planets_response = [] - for planet in planets_list: - planets_response.append(planet.convert_to_dict()) - return jsonify(planets_response), 200 - -@planets_bp.route("/", methods = ["GET"]) -def get_planet_by_id(planet_id): - planet = validate_planet(planet_id) - return jsonify(planet.convert_to_dict(), 200) diff --git a/app/routes/__init__.py b/app/routes/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py new file mode 100644 index 000000000..8fbaec5bf --- /dev/null +++ b/app/routes/planet_routes.py @@ -0,0 +1,56 @@ +from app import db +from app.models.planet import Planet +from flask import Blueprint, jsonify, abort, make_response, request + +planets_bp = Blueprint("planets_bp", __name__, url_prefix = "/planets") + +@planets_bp.route("", methods = ["POST"]) +def create_planet(): + planet_value = request.get_json() + new_planet = Planet( + name = planet_value["name"], + livable = planet_value["livable"], + number_of_moons = planet_value["number_of_moons"], + length_of_year = planet_value["length_of_year"], + namesake = planet_value["namesake"], + atmosphere = planet_value["atmosphere"], + diameter = planet_value["diameter"], + description = planet_value["description"]) + + if "name" not in planet_value \ + or "livable" not in planet_value \ + or "number_of_moons" not in planet_value \ + or "length_of_year" not in planet_value \ + or "namesake" not in planet_value \ + or "atmosphere" not in planet_value \ + or "diameter" not in planet_value \ + or "description" not in planet_value: + return make_response(f"Invalid request", 400) + + db.session.add(new_planet) + db.session.commit() + return make_response(f"Planet {new_planet.name} succesfully created", 201) + +@planets_bp.route("", methods = ["GET"]) +def get_all_planets(): + all_planets = Planet.query.all() + planet_response = [] + for planet in all_planets: + planet_response.append( + { + "id": planet.id, + "name": planet.name, + "livable": planet.livable, + "number_of_moons": planet.number_of_moons, + "length_of_year": planet.length_of_year, + "namesake": planet.namesake, + "atmosphere": planet.atmosphere, + "diameter": planet.diameter, + "description": planet.description + }) + return jsonify(planet_response), 200 + +# @planets_bp.route("/", methods = ["GET"]) +# def get_planet_by_id(planet_id): +# planet = validate_planet(planet_id) +# return jsonify(planet.convert_to_dict(), 200) diff --git a/migrations/README b/migrations/README new file mode 100644 index 000000000..98e4f9c44 --- /dev/null +++ b/migrations/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/migrations/alembic.ini b/migrations/alembic.ini new file mode 100644 index 000000000..f8ed4801f --- /dev/null +++ b/migrations/alembic.ini @@ -0,0 +1,45 @@ +# A generic, single database configuration. + +[alembic] +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/migrations/env.py b/migrations/env.py new file mode 100644 index 000000000..8b3fb3353 --- /dev/null +++ b/migrations/env.py @@ -0,0 +1,96 @@ +from __future__ import with_statement + +import logging +from logging.config import fileConfig + +from sqlalchemy import engine_from_config +from sqlalchemy import pool +from flask import current_app + +from alembic import context + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) +logger = logging.getLogger('alembic.env') + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +config.set_main_option( + 'sqlalchemy.url', + str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%')) +target_metadata = current_app.extensions['migrate'].db.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, target_metadata=target_metadata, literal_binds=True + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + + # this callback is used to prevent an auto-migration from being generated + # when there are no changes to the schema + # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html + def process_revision_directives(context, revision, directives): + if getattr(config.cmd_opts, 'autogenerate', False): + script = directives[0] + if script.upgrade_ops.is_empty(): + directives[:] = [] + logger.info('No changes in schema detected.') + + connectable = engine_from_config( + config.get_section(config.config_ini_section), + prefix='sqlalchemy.', + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=target_metadata, + process_revision_directives=process_revision_directives, + **current_app.extensions['migrate'].configure_args + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/migrations/script.py.mako b/migrations/script.py.mako new file mode 100644 index 000000000..2c0156303 --- /dev/null +++ b/migrations/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} From ce89a0f99cfde40cc530034fff5818f7699956e8 Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 20 Dec 2022 20:38:44 -0800 Subject: [PATCH 08/85] wave 03 done --- app/__init__.py | 14 ++- app/models/__init__.py | 0 app/models/planets.py | 32 +++++++ app/planets.py | 25 ----- app/routes.py | 63 ++++++++---- migrations/README | 1 + migrations/alembic.ini | 45 +++++++++ migrations/env.py | 96 +++++++++++++++++++ migrations/script.py.mako | 24 +++++ .../121486141f79_adds_planet_model.py | 34 +++++++ .../1aeb2d9c2e75_update_planet_model.py | 28 ++++++ planets.sql | 9 ++ 12 files changed, 327 insertions(+), 44 deletions(-) create mode 100644 app/models/__init__.py create mode 100644 app/models/planets.py delete mode 100644 app/planets.py create mode 100644 migrations/README create mode 100644 migrations/alembic.ini create mode 100644 migrations/env.py create mode 100644 migrations/script.py.mako create mode 100644 migrations/versions/121486141f79_adds_planet_model.py create mode 100644 migrations/versions/1aeb2d9c2e75_update_planet_model.py create mode 100644 planets.sql diff --git a/app/__init__.py b/app/__init__.py index 02075e69a..f7112018d 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,10 +1,20 @@ from flask import Flask - - +from flask_sqlalchemy import SQLAlchemy +from flask_migrate import Migrate +db = SQLAlchemy() +migrate = Migrate() def create_app(test_config=None): app = Flask(__name__) + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://postgres:postgres@localhost:5432/solar_system_development' + + db.init_app(app) + migrate.init_app(app, db) + + from app.models.planets import Planet + from .routes import planets_bp app.register_blueprint(planets_bp) diff --git a/app/models/__init__.py b/app/models/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/app/models/planets.py b/app/models/planets.py new file mode 100644 index 000000000..7da18fa0f --- /dev/null +++ b/app/models/planets.py @@ -0,0 +1,32 @@ +from app import db +class Planet(db.Model): + id = db.Column(db.Integer, primary_key=True, autoincrement=True) + name = db.Column(db.String) + atmosphere = db.Column(db.String) + diameter = db.Column(db.Integer) + description = db.Column(db.Text) + + + # def __init__(self, id , name, atmosphere, diameter,description): + # self.id = id + # self.name = name + # self.atmosphere = atmosphere + # self.diameter = diameter + # self.description = description + + # def convert_to_dict(self): + # return { + # "id":self.id, + # "name":self.name, + # "atmosphere":self.atmosphere, + # "diameter":self.diameter, + # "description":self.description + # } +# planets_list = [ +# Planet(1,"Mercury","minimal","0.383","The smallest planet in our solar system and nearest to the Sun."), +# Planet(2,"Venus","CO2, N2","0.949","Venus is the second planet from the Sun and is Earth’s closest planetary neighbor."), +# Planet(3,"Earth","N2, O2, Ar","1.000","Our home planet is the third planet from the Sun."), +# Planet(4,"Mars","CO2, N2, Ar","0.532","Mars is the fourth planet from the Sun – a dusty, cold, desert world with a very thin atmosphere."), +# Planet(5,"Jupiter","H2, He","11.209","Jupiter has a long history of surprising scientists."), +# Planet(6,"Saturn","H2, He","9.449","Saturn is the sixth planet from the Sun and the second-largest planet in our solar system.") +# ] \ No newline at end of file diff --git a/app/planets.py b/app/planets.py deleted file mode 100644 index 9b51e4ded..000000000 --- a/app/planets.py +++ /dev/null @@ -1,25 +0,0 @@ -class Planet: - def __init__(self, id , name, atmosphere, diameter,description): - self.id = id - self.name = name - self.atmosphere = atmosphere - self.diameter = diameter - self.description = description - - def convert_to_dict(self): - return { - "id":self.id, - "name":self.name, - "atmosphere":self.atmosphere, - "diameter":self.diameter, - "description":self.description - } - -planets_list = [ - Planet(1,"Mercury","minimal","0.383","The smallest planet in our solar system and nearest to the Sun, Mercury is only slightly larger than Earth's Moon."), - Planet(2,"Venus","CO2, N2","0.949","Venus is the second planet from the Sun and is Earth’s closest planetary neighbor. It’s one of the four inner, terrestrial (or rocky) planets, and it’s often called Earth’s twin because it’s similar in size and density. These are not identical twins, however – there are radical differences between the two worlds."), - Planet(3,"Earth","N2, O2, Ar","1.000","Our home planet is the third planet from the Sun, and the only place we know of so far that’s inhabited by living things."), - Planet(4,"Mars","CO2, N2, Ar","0.532","Mars is the fourth planet from the Sun – a dusty, cold, desert world with a very thin atmosphere. Mars is also a dynamic planet with seasons, polar ice caps, canyons, extinct volcanoes, and evidence that it was even more active in the past."), - Planet(5,"Jupiter","H2, He","11.209","Jupiter has a long history of surprising scientists – all the way back to 1610 when Galileo Galilei found the first moons beyond Earth. That discovery changed the way we see the universe."), - Planet(6,"Saturn","H2, He","9.449","Saturn is the sixth planet from the Sun and the second-largest planet in our solar system.") -] \ No newline at end of file diff --git a/app/routes.py b/app/routes.py index a1dc39133..cbafeab3e 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,27 +1,56 @@ -from flask import Blueprint, jsonify, abort, make_response +from flask import Blueprint, jsonify, abort, make_response, request +from app import db +from app.models.planets import Planet -from .planets import Planet, planets_list + +# from .models.planets import Planet, planets_list planets_bp = Blueprint("all_planets", __name__, url_prefix = "/planets") -def validate_planet(planet_id): - try: - planet_id = int(planet_id) - except: - abort(make_response({"massage":f"The planet_id {planet_id} is not valid."}, 400)) +@planets_bp.route("",methods=["POST"]) +def add_new_planet(): + request_body = request.get_json() + + new_planet = Planet( + id = request_body["id"], + description = request_body["description"], + name = request_body["name"], + diameter = request_body["diameter"], + atmosphere = request_body["atmosphere"]) + + db.session.add(new_planet) + db.session.commit() + + return make_response(f"Planet {new_planet.name} successfully created.", 201) + + + + +# def validate_planet(planet_id): +# try: +# planet_id = int(planet_id) +# except: +# abort(make_response({"massage":f"The planet_id {planet_id} is not valid."}, 400)) - for planet in planets_list: - if planet.id == planet_id: - return planet - abort(make_response({"massage":f"The planet with id {planet_id} not exist."}, 404)) +# for planet in planets_list: +# if planet.id == planet_id: +# return planet +# abort(make_response({"massage":f"The planet with id {planet_id} not exist."}, 404)) @planets_bp.route("", methods = ["GET"]) def get_all_planets(): planets_response = [] - for planet in planets_list: - planets_response.append(planet.convert_to_dict()) + planets = Planet.query.all() + for planet in planets: + planets_response.append({ + "id": planet.id, + "name":planet.name, + "atmosphere":planet.atmosphere, + "diameter":planet.diameter, + "description":planet.description + }) return jsonify(planets_response), 200 -@planets_bp.route("/", methods = ["GET"]) -def get_planet_by_id(planet_id): - planet = validate_planet(planet_id) - return jsonify(planet.convert_to_dict(), 200) +# @planets_bp.route("/", methods = ["GET"]) +# def get_planet_by_id(planet_id): +# planet = validate_planet(planet_id) +# return jsonify(planet.convert_to_dict(), 200) diff --git a/migrations/README b/migrations/README new file mode 100644 index 000000000..98e4f9c44 --- /dev/null +++ b/migrations/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/migrations/alembic.ini b/migrations/alembic.ini new file mode 100644 index 000000000..f8ed4801f --- /dev/null +++ b/migrations/alembic.ini @@ -0,0 +1,45 @@ +# A generic, single database configuration. + +[alembic] +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/migrations/env.py b/migrations/env.py new file mode 100644 index 000000000..8b3fb3353 --- /dev/null +++ b/migrations/env.py @@ -0,0 +1,96 @@ +from __future__ import with_statement + +import logging +from logging.config import fileConfig + +from sqlalchemy import engine_from_config +from sqlalchemy import pool +from flask import current_app + +from alembic import context + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) +logger = logging.getLogger('alembic.env') + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +config.set_main_option( + 'sqlalchemy.url', + str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%')) +target_metadata = current_app.extensions['migrate'].db.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, target_metadata=target_metadata, literal_binds=True + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + + # this callback is used to prevent an auto-migration from being generated + # when there are no changes to the schema + # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html + def process_revision_directives(context, revision, directives): + if getattr(config.cmd_opts, 'autogenerate', False): + script = directives[0] + if script.upgrade_ops.is_empty(): + directives[:] = [] + logger.info('No changes in schema detected.') + + connectable = engine_from_config( + config.get_section(config.config_ini_section), + prefix='sqlalchemy.', + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=target_metadata, + process_revision_directives=process_revision_directives, + **current_app.extensions['migrate'].configure_args + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/migrations/script.py.mako b/migrations/script.py.mako new file mode 100644 index 000000000..2c0156303 --- /dev/null +++ b/migrations/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/migrations/versions/121486141f79_adds_planet_model.py b/migrations/versions/121486141f79_adds_planet_model.py new file mode 100644 index 000000000..15b4d5a86 --- /dev/null +++ b/migrations/versions/121486141f79_adds_planet_model.py @@ -0,0 +1,34 @@ +"""adds Planet model + +Revision ID: 121486141f79 +Revises: +Create Date: 2022-12-20 19:05:14.734348 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '121486141f79' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('planet', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('description', sa.Text(), nullable=True), + sa.Column('diameter', sa.Integer(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('planet') + # ### end Alembic commands ### diff --git a/migrations/versions/1aeb2d9c2e75_update_planet_model.py b/migrations/versions/1aeb2d9c2e75_update_planet_model.py new file mode 100644 index 000000000..7cc8e1365 --- /dev/null +++ b/migrations/versions/1aeb2d9c2e75_update_planet_model.py @@ -0,0 +1,28 @@ +"""update Planet model + +Revision ID: 1aeb2d9c2e75 +Revises: 121486141f79 +Create Date: 2022-12-20 19:52:02.304999 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '1aeb2d9c2e75' +down_revision = '121486141f79' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('planet', sa.Column('atmosphere', sa.String(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('planet', 'atmosphere') + # ### end Alembic commands ### diff --git a/planets.sql b/planets.sql new file mode 100644 index 000000000..4978587d6 --- /dev/null +++ b/planets.sql @@ -0,0 +1,9 @@ +Name,Surface Area,Moons,Distance from Sun,Namesake +Jupiter,23710000000,79,483300000,"King of the Roman gods, aka Zeus." +Mars,55910000,2,141000000,"Roman god of war, aka Ares." +Venus,67400000,0,177700000,"Roman goddess of love, aka Aphrodite." +Earth,57510000,1,93123021,"A variation on the word ""ground"" in several languages." +Neptune,2941000000,14,2793000000,"Roman god of the sea aka, Poseidon." +Saturn,16490000000,62,890900000,"Jupiter's father and titan aka, Chronos." +Uranus,3171000000,27,1784000000,"Greek personificatino of the sky or heavens, aka Caelus." +Mercury,28880000,0,35980000,"Roman god of travellers, aka Hermes." From e709c0d40b9466ef176c82199d2afea21a166232 Mon Sep 17 00:00:00 2001 From: annadu Date: Wed, 21 Dec 2022 08:13:12 -0800 Subject: [PATCH 09/85] wave 3 done --- app/models/planets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/planets.py b/app/models/planets.py index 7da18fa0f..5e2d21eee 100644 --- a/app/models/planets.py +++ b/app/models/planets.py @@ -3,8 +3,9 @@ class Planet(db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String) atmosphere = db.Column(db.String) - diameter = db.Column(db.Integer) + diameter = db.Column(db.Float) description = db.Column(db.Text) + # def __init__(self, id , name, atmosphere, diameter,description): From 98f167e63a80fe85a8880cfffac6b853a0fc5adc Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Wed, 21 Dec 2022 11:07:45 -0800 Subject: [PATCH 10/85] add routes: read_one_planet, update, delete --- app/routes/planet_routes.py | 71 ++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 8fbaec5bf..66fb76b83 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -8,8 +8,7 @@ def create_planet(): planet_value = request.get_json() new_planet = Planet( - name = planet_value["name"], - livable = planet_value["livable"], + name = planet_value["name"], number_of_moons = planet_value["number_of_moons"], length_of_year = planet_value["length_of_year"], namesake = planet_value["namesake"], @@ -18,7 +17,6 @@ def create_planet(): description = planet_value["description"]) if "name" not in planet_value \ - or "livable" not in planet_value \ or "number_of_moons" not in planet_value \ or "length_of_year" not in planet_value \ or "namesake" not in planet_value \ @@ -40,7 +38,6 @@ def get_all_planets(): { "id": planet.id, "name": planet.name, - "livable": planet.livable, "number_of_moons": planet.number_of_moons, "length_of_year": planet.length_of_year, "namesake": planet.namesake, @@ -50,7 +47,65 @@ def get_all_planets(): }) return jsonify(planet_response), 200 -# @planets_bp.route("/", methods = ["GET"]) -# def get_planet_by_id(planet_id): -# planet = validate_planet(planet_id) -# return jsonify(planet.convert_to_dict(), 200) + +def validate_planet(planet_id): + try: + planet_id = int(planet_id) + except: + abort(make_response({"message":f"Planet {planet_id} invalid"}, 400)) + planet = Planet.query.get(planet_id) + if not planet: + abort(make_response({"message":f"Planet {planet_id} not found"}, 404)) + return planet + +# Read one planet +@planets_bp.route("/",methods=["GET"] ) +def get_one_planet(planet_id): + planet = validate_planet(planet_id) + return { + "id": planet.id, + "name": planet.name, + "number_of_moons": planet.number_of_moons, + "length_of_year": planet.length_of_year, + "namesake": planet.namesake, + "atmosphere": planet.atmosphere, + "diameter": planet.diameter, + "description": planet.description + } + +# update one planet +@planets_bp.route("/",methods=["PUT"] ) +def update_planet(planet_id): + planet = validate_planet(planet_id) + + request_body = request.get_json() + + if "name" not in request_body \ + or "number_of_moons" not in request_body \ + or "length_of_year" not in request_body \ + or "namesake" not in request_body \ + or "atmosphere" not in request_body \ + or "diameter" not in request_body \ + or "description" not in request_body: + return make_response(f"Invalid request", 400) + + planet.name = request_body["name"], + planet.number_of_moons = request_body["number_of_moons"], + planet.length_of_year = request_body["length_of_year"], + planet.namesake = request_body["namesake"], + planet.atmosphere = request_body["atmosphere"], + planet.meter = request_body["diameter"], + planet.description = request_body["description"] + + db.session.commit() + + return make_response(f"Planet {planet.id} successfully update.") + + # Delete one planet +@planets_bp.route("/",methods=["DELETE"] ) +def delete_planet(planet_id): + planet = validate_planet(planet_id) + db.session.delete(planet) + db.session.commit() + + return make_response(f"Planet {planet.id} successfully delete.") From c6307d247380c68fa4365b55e34cfe20eef8416d Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Wed, 21 Dec 2022 11:08:49 -0800 Subject: [PATCH 11/85] wave4 complite --- app/models/planet.py | 2 +- app/planets_data.csv | 82 ++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 2 +- 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 app/planets_data.csv diff --git a/app/models/planet.py b/app/models/planet.py index 7ce0483a3..05369fd45 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -3,7 +3,7 @@ class Planet(db.Model): id = db.Column(db.Integer, primary_key = True, autoincrement = True) name = db.Column(db.String, nullable = False) - livable = db.Column(db.Boolean, default = False) + #livable = db.Column(db.Boolean, default = False) number_of_moons = db.Column(db.Integer, nullable = True) length_of_year = db.Column(db.Integer, nullable = False) namesake = db.Column(db.String, nullable = False) diff --git a/app/planets_data.csv b/app/planets_data.csv new file mode 100644 index 000000000..02b7142d4 --- /dev/null +++ b/app/planets_data.csv @@ -0,0 +1,82 @@ +[ + { + "atmosphere": "minimal", + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + "diameter": "0.383", + "id": 1, + "length_of_year": 88, + "name": "Mercury", + "namesake": "Roman God Of Speed", + "number_of_moons": 0 + }, + { + "atmosphere": "CO2, N2", + "description": "Venus spins slowly in the opposite direction from most planets.", + "diameter": "0.949", + "id": 3, + "length_of_year": 225, + "name": "Venus", + "namesake": "Roman Goddess Of Love", + "number_of_moons": 0 + }, + { + "atmosphere": "N2, O2, Ar", + "description": "Earth — our home planet.", + "diameter": "1.000", + "id": 4, + "length_of_year": 365, + "name": "Earth", + "namesake": "The Ground", + "number_of_moons": 1 + }, + { + "atmosphere": "CO2, N2, Ar", + "description": "Mars is a dusty, cold, desert world with a very thin atmosphere.", + "diameter": "0.532", + "id": 5, + "length_of_year": 687, + "name": "Mars", + "namesake": "Roman God Of War", + "number_of_moons": 2 + }, + { + "atmosphere": "H2, He", + "description": "Jupiter is more than twice as massive than the other planets of our solar system combined.", + "diameter": "11.209", + "id": 6, + "length_of_year": 687, + "name": "Jupiter", + "namesake": "King Of The Roman Gods", + "number_of_moons": 79 + }, + { + "atmosphere": "H2, He", + "description": "Adorned with a dazzling, complex system of icy rings, Saturn is unique in our solar system.", + "diameter": "9.449", + "id": 7, + "length_of_year": 10756, + "name": "Saturn", + "namesake": "Father Of Jupiter", + "number_of_moons": 62 + }, + { + "atmosphere": "H2, He, CH4", + "description": "Uranus—seventh planet from the Sun—rotates at a nearly 90-degree angle from the plane of its orbit.", + "diameter": "4.007", + "id": 8, + "length_of_year": 30687, + "name": "Uranus", + "namesake": "Greek God Of The Sky", + "number_of_moons": 27 + }, + { + "atmosphere": "H2, He, CH4", + "description": "Neptune—the eighth and most distant major planet orbiting our Sun—is dark, cold and whipped by supersonic winds.", + "diameter": "3.883", + "id": 9, + "length_of_year": 60190, + "name": "Neptune", + "namesake": "Roman God Of The Sea", + "number_of_moons": 14 + } +] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index fba2b3e38..d93ba05c9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ blinker==1.4 certifi==2020.12.5 chardet==4.0.0 click==7.1.2 -Flask==1.1.2 +Flask==2.1.0 Flask-Migrate==2.6.0 Flask-SQLAlchemy==2.4.4 idna==2.10 From 9532ffcbf831fa96900b037e3475e53b44bd3d70 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Wed, 21 Dec 2022 11:36:46 -0800 Subject: [PATCH 12/85] Added comments and helper functions --- app/routes/planet_routes.py | 75 +++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 66fb76b83..01ee6efba 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -4,18 +4,23 @@ planets_bp = Blueprint("planets_bp", __name__, url_prefix = "/planets") -@planets_bp.route("", methods = ["POST"]) -def create_planet(): - planet_value = request.get_json() - new_planet = Planet( - name = planet_value["name"], - number_of_moons = planet_value["number_of_moons"], - length_of_year = planet_value["length_of_year"], - namesake = planet_value["namesake"], - atmosphere = planet_value["atmosphere"], - diameter = planet_value["diameter"], - description = planet_value["description"]) +# Helper functions +# Validating the id of the planet: id needs to be int and exists the planet with the id. +# Returning the valid Planet instance if valid id +def validate_planet(planet_id): + try: + planet_id = int(planet_id) + except: + abort(make_response({"message":f"Planet {planet_id} invalid"}, 400)) + planet = Planet.query.get(planet_id) + if not planet: + abort(make_response({"message":f"Planet {planet_id} not found"}, 404)) + return planet + +# Validating the user input to create or update the table planet +# Returning the valid JSON if valid input +def validate_input(planet_value): if "name" not in planet_value \ or "number_of_moons" not in planet_value \ or "length_of_year" not in planet_value \ @@ -23,12 +28,28 @@ def create_planet(): or "atmosphere" not in planet_value \ or "diameter" not in planet_value \ or "description" not in planet_value: - return make_response(f"Invalid request", 400) + return abort(make_response(f"Invalid request", 400)) + return planet_value +# Routes functions +# Creating new record in the database Planet +@planets_bp.route("", methods = ["POST"]) +def create_planet(): + planet_value = validate_input(request.get_json()) + new_planet = Planet( + name = planet_value["name"], + number_of_moons = planet_value["number_of_moons"], + length_of_year = planet_value["length_of_year"], + namesake = planet_value["namesake"], + atmosphere = planet_value["atmosphere"], + diameter = planet_value["diameter"], + description = planet_value["description"]) db.session.add(new_planet) db.session.commit() return make_response(f"Planet {new_planet.name} succesfully created", 201) +# Get all planets info +# Return JSON list @planets_bp.route("", methods = ["GET"]) def get_all_planets(): all_planets = Planet.query.all() @@ -47,18 +68,8 @@ def get_all_planets(): }) return jsonify(planet_response), 200 - -def validate_planet(planet_id): - try: - planet_id = int(planet_id) - except: - abort(make_response({"message":f"Planet {planet_id} invalid"}, 400)) - planet = Planet.query.get(planet_id) - if not planet: - abort(make_response({"message":f"Planet {planet_id} not found"}, 404)) - return planet - -# Read one planet +# Read one planet +# Return one panet info in JSON format @planets_bp.route("/",methods=["GET"] ) def get_one_planet(planet_id): planet = validate_planet(planet_id) @@ -73,21 +84,11 @@ def get_one_planet(planet_id): "description": planet.description } -# update one planet +# Update one planet @planets_bp.route("/",methods=["PUT"] ) def update_planet(planet_id): planet = validate_planet(planet_id) - - request_body = request.get_json() - - if "name" not in request_body \ - or "number_of_moons" not in request_body \ - or "length_of_year" not in request_body \ - or "namesake" not in request_body \ - or "atmosphere" not in request_body \ - or "diameter" not in request_body \ - or "description" not in request_body: - return make_response(f"Invalid request", 400) + request_body = validate_input(request.get_json()) planet.name = request_body["name"], planet.number_of_moons = request_body["number_of_moons"], @@ -101,7 +102,7 @@ def update_planet(planet_id): return make_response(f"Planet {planet.id} successfully update.") - # Delete one planet +# Delete one planet @planets_bp.route("/",methods=["DELETE"] ) def delete_planet(planet_id): planet = validate_planet(planet_id) From d854dcb9986f43900dd4d8569b251ae27ae455d3 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Wed, 21 Dec 2022 11:49:29 -0800 Subject: [PATCH 13/85] Added validation for user's input datatypes --- app/routes/planet_routes.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 01ee6efba..8569b1482 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -21,13 +21,13 @@ def validate_planet(planet_id): # Validating the user input to create or update the table planet # Returning the valid JSON if valid input def validate_input(planet_value): - if "name" not in planet_value \ - or "number_of_moons" not in planet_value \ - or "length_of_year" not in planet_value \ - or "namesake" not in planet_value \ - or "atmosphere" not in planet_value \ - or "diameter" not in planet_value \ - or "description" not in planet_value: + if "name" not in planet_value or not isinstance(planet_value["name"], str) \ + or "number_of_moons" not in planet_value or not isinstance(planet_value["number_of_moons"], int) \ + or "length_of_year" not in planet_value or not isinstance(planet_value["length_of_year"], int) \ + or "namesake" not in planet_value or not isinstance(planet_value["namesake"], str) \ + or "atmosphere" not in planet_value or not isinstance(planet_value["atmosphere"], str) \ + or "diameter" not in planet_value or not isinstance(planet_value["diameter"], str) \ + or "description" not in planet_value or not isinstance(planet_value["description"], str): return abort(make_response(f"Invalid request", 400)) return planet_value From 7d773e850548033750e25091fa87fd96888f7f68 Mon Sep 17 00:00:00 2001 From: annadu Date: Wed, 21 Dec 2022 12:20:35 -0800 Subject: [PATCH 14/85] change class planet --- app/__init__.py | 4 +-- app/models/planet.py | 12 ++++++++ app/models/planets.py | 33 ---------------------- app/routes.py | 56 ------------------------------------- app/routes/__init__.py | 0 app/routes/planet_routes.py | 56 +++++++++++++++++++++++++++++++++++++ 6 files changed, 70 insertions(+), 91 deletions(-) create mode 100644 app/models/planet.py delete mode 100644 app/models/planets.py delete mode 100644 app/routes.py create mode 100644 app/routes/__init__.py create mode 100644 app/routes/planet_routes.py diff --git a/app/__init__.py b/app/__init__.py index f7112018d..bd563a7e0 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -13,9 +13,9 @@ def create_app(test_config=None): db.init_app(app) migrate.init_app(app, db) - from app.models.planets import Planet + from app.models.planet import Planet - from .routes import planets_bp + from .routes.planet_routes import planets_bp app.register_blueprint(planets_bp) return app diff --git a/app/models/planet.py b/app/models/planet.py new file mode 100644 index 000000000..283a9a1db --- /dev/null +++ b/app/models/planet.py @@ -0,0 +1,12 @@ +from app import db + +class Planet(db.Model): + id = db.Column(db.Integer, primary_key = True, autoincrement = True) + name = db.Column(db.String, nullable = False) + livable = db.Column(db.Boolean, default = False) + number_of_moons = db.Column(db.Integer, nullable = True) + length_of_year = db.Column(db.Integer, nullable = False) + namesake = db.Column(db.String, nullable = False) + atmosphere = db.Column(db.String, nullable = False) + diameter = db.Column(db.String, nullable = False) + description = db.Column(db.String, nullable = False) \ No newline at end of file diff --git a/app/models/planets.py b/app/models/planets.py deleted file mode 100644 index 5e2d21eee..000000000 --- a/app/models/planets.py +++ /dev/null @@ -1,33 +0,0 @@ -from app import db -class Planet(db.Model): - id = db.Column(db.Integer, primary_key=True, autoincrement=True) - name = db.Column(db.String) - atmosphere = db.Column(db.String) - diameter = db.Column(db.Float) - description = db.Column(db.Text) - - - - # def __init__(self, id , name, atmosphere, diameter,description): - # self.id = id - # self.name = name - # self.atmosphere = atmosphere - # self.diameter = diameter - # self.description = description - - # def convert_to_dict(self): - # return { - # "id":self.id, - # "name":self.name, - # "atmosphere":self.atmosphere, - # "diameter":self.diameter, - # "description":self.description - # } -# planets_list = [ -# Planet(1,"Mercury","minimal","0.383","The smallest planet in our solar system and nearest to the Sun."), -# Planet(2,"Venus","CO2, N2","0.949","Venus is the second planet from the Sun and is Earth’s closest planetary neighbor."), -# Planet(3,"Earth","N2, O2, Ar","1.000","Our home planet is the third planet from the Sun."), -# Planet(4,"Mars","CO2, N2, Ar","0.532","Mars is the fourth planet from the Sun – a dusty, cold, desert world with a very thin atmosphere."), -# Planet(5,"Jupiter","H2, He","11.209","Jupiter has a long history of surprising scientists."), -# Planet(6,"Saturn","H2, He","9.449","Saturn is the sixth planet from the Sun and the second-largest planet in our solar system.") -# ] \ No newline at end of file diff --git a/app/routes.py b/app/routes.py deleted file mode 100644 index cbafeab3e..000000000 --- a/app/routes.py +++ /dev/null @@ -1,56 +0,0 @@ -from flask import Blueprint, jsonify, abort, make_response, request -from app import db -from app.models.planets import Planet - - -# from .models.planets import Planet, planets_list -planets_bp = Blueprint("all_planets", __name__, url_prefix = "/planets") - -@planets_bp.route("",methods=["POST"]) -def add_new_planet(): - request_body = request.get_json() - - new_planet = Planet( - id = request_body["id"], - description = request_body["description"], - name = request_body["name"], - diameter = request_body["diameter"], - atmosphere = request_body["atmosphere"]) - - db.session.add(new_planet) - db.session.commit() - - return make_response(f"Planet {new_planet.name} successfully created.", 201) - - - - -# def validate_planet(planet_id): -# try: -# planet_id = int(planet_id) -# except: -# abort(make_response({"massage":f"The planet_id {planet_id} is not valid."}, 400)) - -# for planet in planets_list: -# if planet.id == planet_id: -# return planet -# abort(make_response({"massage":f"The planet with id {planet_id} not exist."}, 404)) - -@planets_bp.route("", methods = ["GET"]) -def get_all_planets(): - planets_response = [] - planets = Planet.query.all() - for planet in planets: - planets_response.append({ - "id": planet.id, - "name":planet.name, - "atmosphere":planet.atmosphere, - "diameter":planet.diameter, - "description":planet.description - }) - return jsonify(planets_response), 200 - -# @planets_bp.route("/", methods = ["GET"]) -# def get_planet_by_id(planet_id): -# planet = validate_planet(planet_id) -# return jsonify(planet.convert_to_dict(), 200) diff --git a/app/routes/__init__.py b/app/routes/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py new file mode 100644 index 000000000..8fbaec5bf --- /dev/null +++ b/app/routes/planet_routes.py @@ -0,0 +1,56 @@ +from app import db +from app.models.planet import Planet +from flask import Blueprint, jsonify, abort, make_response, request + +planets_bp = Blueprint("planets_bp", __name__, url_prefix = "/planets") + +@planets_bp.route("", methods = ["POST"]) +def create_planet(): + planet_value = request.get_json() + new_planet = Planet( + name = planet_value["name"], + livable = planet_value["livable"], + number_of_moons = planet_value["number_of_moons"], + length_of_year = planet_value["length_of_year"], + namesake = planet_value["namesake"], + atmosphere = planet_value["atmosphere"], + diameter = planet_value["diameter"], + description = planet_value["description"]) + + if "name" not in planet_value \ + or "livable" not in planet_value \ + or "number_of_moons" not in planet_value \ + or "length_of_year" not in planet_value \ + or "namesake" not in planet_value \ + or "atmosphere" not in planet_value \ + or "diameter" not in planet_value \ + or "description" not in planet_value: + return make_response(f"Invalid request", 400) + + db.session.add(new_planet) + db.session.commit() + return make_response(f"Planet {new_planet.name} succesfully created", 201) + +@planets_bp.route("", methods = ["GET"]) +def get_all_planets(): + all_planets = Planet.query.all() + planet_response = [] + for planet in all_planets: + planet_response.append( + { + "id": planet.id, + "name": planet.name, + "livable": planet.livable, + "number_of_moons": planet.number_of_moons, + "length_of_year": planet.length_of_year, + "namesake": planet.namesake, + "atmosphere": planet.atmosphere, + "diameter": planet.diameter, + "description": planet.description + }) + return jsonify(planet_response), 200 + +# @planets_bp.route("/", methods = ["GET"]) +# def get_planet_by_id(planet_id): +# planet = validate_planet(planet_id) +# return jsonify(planet.convert_to_dict(), 200) From 83ce4d219d4dbd7e84e71fe394cad94118871877 Mon Sep 17 00:00:00 2001 From: annadu Date: Wed, 21 Dec 2022 12:32:53 -0800 Subject: [PATCH 15/85] delete wrong data --- planets.sql | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 planets.sql diff --git a/planets.sql b/planets.sql deleted file mode 100644 index 4978587d6..000000000 --- a/planets.sql +++ /dev/null @@ -1,9 +0,0 @@ -Name,Surface Area,Moons,Distance from Sun,Namesake -Jupiter,23710000000,79,483300000,"King of the Roman gods, aka Zeus." -Mars,55910000,2,141000000,"Roman god of war, aka Ares." -Venus,67400000,0,177700000,"Roman goddess of love, aka Aphrodite." -Earth,57510000,1,93123021,"A variation on the word ""ground"" in several languages." -Neptune,2941000000,14,2793000000,"Roman god of the sea aka, Poseidon." -Saturn,16490000000,62,890900000,"Jupiter's father and titan aka, Chronos." -Uranus,3171000000,27,1784000000,"Greek personificatino of the sky or heavens, aka Caelus." -Mercury,28880000,0,35980000,"Roman god of travellers, aka Hermes." From 89653de075ad0b334b0235869bced207fd88e777 Mon Sep 17 00:00:00 2001 From: annadu Date: Wed, 21 Dec 2022 12:33:09 -0800 Subject: [PATCH 16/85] update with kate --- app/planets_data.csv | 82 ++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 2 +- 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 app/planets_data.csv diff --git a/app/planets_data.csv b/app/planets_data.csv new file mode 100644 index 000000000..02b7142d4 --- /dev/null +++ b/app/planets_data.csv @@ -0,0 +1,82 @@ +[ + { + "atmosphere": "minimal", + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + "diameter": "0.383", + "id": 1, + "length_of_year": 88, + "name": "Mercury", + "namesake": "Roman God Of Speed", + "number_of_moons": 0 + }, + { + "atmosphere": "CO2, N2", + "description": "Venus spins slowly in the opposite direction from most planets.", + "diameter": "0.949", + "id": 3, + "length_of_year": 225, + "name": "Venus", + "namesake": "Roman Goddess Of Love", + "number_of_moons": 0 + }, + { + "atmosphere": "N2, O2, Ar", + "description": "Earth — our home planet.", + "diameter": "1.000", + "id": 4, + "length_of_year": 365, + "name": "Earth", + "namesake": "The Ground", + "number_of_moons": 1 + }, + { + "atmosphere": "CO2, N2, Ar", + "description": "Mars is a dusty, cold, desert world with a very thin atmosphere.", + "diameter": "0.532", + "id": 5, + "length_of_year": 687, + "name": "Mars", + "namesake": "Roman God Of War", + "number_of_moons": 2 + }, + { + "atmosphere": "H2, He", + "description": "Jupiter is more than twice as massive than the other planets of our solar system combined.", + "diameter": "11.209", + "id": 6, + "length_of_year": 687, + "name": "Jupiter", + "namesake": "King Of The Roman Gods", + "number_of_moons": 79 + }, + { + "atmosphere": "H2, He", + "description": "Adorned with a dazzling, complex system of icy rings, Saturn is unique in our solar system.", + "diameter": "9.449", + "id": 7, + "length_of_year": 10756, + "name": "Saturn", + "namesake": "Father Of Jupiter", + "number_of_moons": 62 + }, + { + "atmosphere": "H2, He, CH4", + "description": "Uranus—seventh planet from the Sun—rotates at a nearly 90-degree angle from the plane of its orbit.", + "diameter": "4.007", + "id": 8, + "length_of_year": 30687, + "name": "Uranus", + "namesake": "Greek God Of The Sky", + "number_of_moons": 27 + }, + { + "atmosphere": "H2, He, CH4", + "description": "Neptune—the eighth and most distant major planet orbiting our Sun—is dark, cold and whipped by supersonic winds.", + "diameter": "3.883", + "id": 9, + "length_of_year": 60190, + "name": "Neptune", + "namesake": "Roman God Of The Sea", + "number_of_moons": 14 + } +] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index fba2b3e38..d93ba05c9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ blinker==1.4 certifi==2020.12.5 chardet==4.0.0 click==7.1.2 -Flask==1.1.2 +Flask==2.1.0 Flask-Migrate==2.6.0 Flask-SQLAlchemy==2.4.4 idna==2.10 From a8f3aad365e4cbfd9ad7b6a016266eb49c3e8384 Mon Sep 17 00:00:00 2001 From: annadu Date: Wed, 21 Dec 2022 12:37:03 -0800 Subject: [PATCH 17/85] change with kate --- app/__init__.py | 5 +- app/models/planet.py | 2 +- app/routes/planet_routes.py | 112 ++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 2 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index e77cc7f89..344211b1b 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,8 +1,11 @@ from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from flask_migrate import Migrate -def create_app(test_config=None): + +def create_app(): app = Flask(__name__) app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False diff --git a/app/models/planet.py b/app/models/planet.py index 079273c4f..ca8a030b9 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -4,7 +4,7 @@ class Planet(db.Model): id = db.Column(db.Integer, primary_key = True, autoincrement = True) name = db.Column(db.String, nullable = False) - livable = db.Column(db.Boolean, default = False) + #livable = db.Column(db.Boolean, default = False) number_of_moons = db.Column(db.Integer, nullable = True) length_of_year = db.Column(db.Integer, nullable = False) namesake = db.Column(db.String, nullable = False) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index e69de29bb..bd7e51316 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -0,0 +1,112 @@ +from app import db +from app.models.planet import Planet +from flask import Blueprint, jsonify, abort, make_response, request + +planets_bp = Blueprint("planets_bp", __name__, url_prefix = "/planets") + +# Helper functions + +# Validating the id of the planet: id needs to be int and exists the planet with the id. +# Returning the valid Planet instance if valid id +def validate_planet(planet_id): + try: + planet_id = int(planet_id) + except: + abort(make_response({"message":f"Planet {planet_id} invalid"}, 400)) + planet = Planet.query.get(planet_id) + if not planet: + abort(make_response({"message":f"Planet {planet_id} not found"}, 404)) + return planet + +# Validating the user input to create or update the table planet +# Returning the valid JSON if valid input +def validate_input(planet_value): + if "name" not in planet_value or not isinstance(planet_value["name"], str) \ + or "number_of_moons" not in planet_value or not isinstance(planet_value["number_of_moons"], int) \ + or "length_of_year" not in planet_value or not isinstance(planet_value["length_of_year"], int) \ + or "namesake" not in planet_value or not isinstance(planet_value["namesake"], str) \ + or "atmosphere" not in planet_value or not isinstance(planet_value["atmosphere"], str) \ + or "diameter" not in planet_value or not isinstance(planet_value["diameter"], str) \ + or "description" not in planet_value or not isinstance(planet_value["description"], str): + return abort(make_response(f"Invalid request", 400)) + return planet_value + +# Routes functions +# Creating new record in the database Planet +@planets_bp.route("", methods = ["POST"]) +def create_planet(): + planet_value = validate_input(request.get_json()) + new_planet = Planet( + name = planet_value["name"], + number_of_moons = planet_value["number_of_moons"], + length_of_year = planet_value["length_of_year"], + namesake = planet_value["namesake"], + atmosphere = planet_value["atmosphere"], + diameter = planet_value["diameter"], + description = planet_value["description"]) + db.session.add(new_planet) + db.session.commit() + return make_response(f"Planet {new_planet.name} succesfully created", 201) + +# Get all planets info +# Return JSON list +@planets_bp.route("", methods = ["GET"]) +def get_all_planets(): + all_planets = Planet.query.all() + planet_response = [] + for planet in all_planets: + planet_response.append( + { + "id": planet.id, + "name": planet.name, + "number_of_moons": planet.number_of_moons, + "length_of_year": planet.length_of_year, + "namesake": planet.namesake, + "atmosphere": planet.atmosphere, + "diameter": planet.diameter, + "description": planet.description + }) + return jsonify(planet_response), 200 + +# Read one planet +# Return one panet info in JSON format +@planets_bp.route("/",methods=["GET"] ) +def get_one_planet(planet_id): + planet = validate_planet(planet_id) + return { + "id": planet.id, + "name": planet.name, + "number_of_moons": planet.number_of_moons, + "length_of_year": planet.length_of_year, + "namesake": planet.namesake, + "atmosphere": planet.atmosphere, + "diameter": planet.diameter, + "description": planet.description + } + +# Update one planet +@planets_bp.route("/",methods=["PUT"] ) +def update_planet(planet_id): + planet = validate_planet(planet_id) + request_body = validate_input(request.get_json()) + + planet.name = request_body["name"], + planet.number_of_moons = request_body["number_of_moons"], + planet.length_of_year = request_body["length_of_year"], + planet.namesake = request_body["namesake"], + planet.atmosphere = request_body["atmosphere"], + planet.meter = request_body["diameter"], + planet.description = request_body["description"] + + db.session.commit() + + return make_response(f"Planet {planet.id} successfully update.") + +# Delete one planet +@planets_bp.route("/",methods=["DELETE"] ) +def delete_planet(planet_id): + planet = validate_planet(planet_id) + db.session.delete(planet) + db.session.commit() + + return make_response(f"Planet {planet.id} successfully delete.") \ No newline at end of file From 96228286b83ad30f89a2b4c80181b9d100f69f74 Mon Sep 17 00:00:00 2001 From: annadu Date: Wed, 21 Dec 2022 12:43:12 -0800 Subject: [PATCH 18/85] planet table created --- app/__init__.py | 3 +- ...c913d5e2a_update_planet_model_with_kate.py | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 migrations/versions/953c913d5e2a_update_planet_model_with_kate.py diff --git a/app/__init__.py b/app/__init__.py index 344211b1b..a54959aac 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -2,7 +2,8 @@ from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate - +db = SQLAlchemy() +migrate = Migrate() def create_app(): diff --git a/migrations/versions/953c913d5e2a_update_planet_model_with_kate.py b/migrations/versions/953c913d5e2a_update_planet_model_with_kate.py new file mode 100644 index 000000000..a62f684b6 --- /dev/null +++ b/migrations/versions/953c913d5e2a_update_planet_model_with_kate.py @@ -0,0 +1,38 @@ +"""update planet model with kate + +Revision ID: 953c913d5e2a +Revises: 1aeb2d9c2e75 +Create Date: 2022-12-21 12:40:21.897814 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '953c913d5e2a' +down_revision = '1aeb2d9c2e75' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('planet', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('name', sa.String(), nullable=False), + sa.Column('number_of_moons', sa.Integer(), nullable=True), + sa.Column('length_of_year', sa.Integer(), nullable=False), + sa.Column('namesake', sa.String(), nullable=False), + sa.Column('atmosphere', sa.String(), nullable=False), + sa.Column('diameter', sa.String(), nullable=False), + sa.Column('description', sa.String(), nullable=False), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('planet') + # ### end Alembic commands ### From 75936eee036c1e3f911b99b47abc41d383b9f3c0 Mon Sep 17 00:00:00 2001 From: annadu Date: Wed, 21 Dec 2022 14:33:34 -0800 Subject: [PATCH 19/85] add new class planet attribute livable, type is boolean test work --- app/models/planet.py | 2 +- app/routes/planet_routes.py | 12 +++++--- ...daedb50_update_planet_model_add_livable.py | 28 +++++++++++++++++++ 3 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 migrations/versions/927e0daedb50_update_planet_model_add_livable.py diff --git a/app/models/planet.py b/app/models/planet.py index ca8a030b9..079273c4f 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -4,7 +4,7 @@ class Planet(db.Model): id = db.Column(db.Integer, primary_key = True, autoincrement = True) name = db.Column(db.String, nullable = False) - #livable = db.Column(db.Boolean, default = False) + livable = db.Column(db.Boolean, default = False) number_of_moons = db.Column(db.Integer, nullable = True) length_of_year = db.Column(db.Integer, nullable = False) namesake = db.Column(db.String, nullable = False) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index bd7e51316..84ff44494 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -43,7 +43,8 @@ def create_planet(): namesake = planet_value["namesake"], atmosphere = planet_value["atmosphere"], diameter = planet_value["diameter"], - description = planet_value["description"]) + description = planet_value["description"], + livable = planet_value["livable"]) db.session.add(new_planet) db.session.commit() return make_response(f"Planet {new_planet.name} succesfully created", 201) @@ -64,7 +65,8 @@ def get_all_planets(): "namesake": planet.namesake, "atmosphere": planet.atmosphere, "diameter": planet.diameter, - "description": planet.description + "description": planet.description, + "livable":planet.livable }) return jsonify(planet_response), 200 @@ -81,7 +83,8 @@ def get_one_planet(planet_id): "namesake": planet.namesake, "atmosphere": planet.atmosphere, "diameter": planet.diameter, - "description": planet.description + "description": planet.description, + "livable":planet.livable } # Update one planet @@ -96,7 +99,8 @@ def update_planet(planet_id): planet.namesake = request_body["namesake"], planet.atmosphere = request_body["atmosphere"], planet.meter = request_body["diameter"], - planet.description = request_body["description"] + planet.description = request_body["description"], + planet.livable = request_body["livable"] db.session.commit() diff --git a/migrations/versions/927e0daedb50_update_planet_model_add_livable.py b/migrations/versions/927e0daedb50_update_planet_model_add_livable.py new file mode 100644 index 000000000..003d7deae --- /dev/null +++ b/migrations/versions/927e0daedb50_update_planet_model_add_livable.py @@ -0,0 +1,28 @@ +"""update planet model add livable + +Revision ID: 927e0daedb50 +Revises: 953c913d5e2a +Create Date: 2022-12-21 12:45:10.302200 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '927e0daedb50' +down_revision = '953c913d5e2a' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('planet', sa.Column('livable', sa.Boolean(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('planet', 'livable') + # ### end Alembic commands ### From 22341682dd5e9ba095328849577f0744d6d36368 Mon Sep 17 00:00:00 2001 From: annadu Date: Thu, 22 Dec 2022 09:32:11 -0800 Subject: [PATCH 20/85] add color attribute --- app/models/planet.py | 3 +- app/routes/planet_routes.py | 12 +++++--- .../versions/c3e5c7fe877e_adds_color.py | 28 +++++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 migrations/versions/c3e5c7fe877e_adds_color.py diff --git a/app/models/planet.py b/app/models/planet.py index 079273c4f..1d0b432b7 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -10,4 +10,5 @@ class Planet(db.Model): namesake = db.Column(db.String, nullable = False) atmosphere = db.Column(db.String, nullable = False) diameter = db.Column(db.String, nullable = False) - description = db.Column(db.String, nullable = False) \ No newline at end of file + description = db.Column(db.String, nullable = False) + color = db.Column(db.String) \ No newline at end of file diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 84ff44494..b09b250c4 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -44,7 +44,8 @@ def create_planet(): atmosphere = planet_value["atmosphere"], diameter = planet_value["diameter"], description = planet_value["description"], - livable = planet_value["livable"]) + livable = planet_value["livable"], + color = planet_value["color"]) db.session.add(new_planet) db.session.commit() return make_response(f"Planet {new_planet.name} succesfully created", 201) @@ -66,7 +67,8 @@ def get_all_planets(): "atmosphere": planet.atmosphere, "diameter": planet.diameter, "description": planet.description, - "livable":planet.livable + "livable":planet.livable, + "color":planet.color }) return jsonify(planet_response), 200 @@ -84,7 +86,8 @@ def get_one_planet(planet_id): "atmosphere": planet.atmosphere, "diameter": planet.diameter, "description": planet.description, - "livable":planet.livable + "livable":planet.livable, + "color":planet.color } # Update one planet @@ -100,7 +103,8 @@ def update_planet(planet_id): planet.atmosphere = request_body["atmosphere"], planet.meter = request_body["diameter"], planet.description = request_body["description"], - planet.livable = request_body["livable"] + planet.livable = request_body["livable"], + planet.color= request_body["color"] db.session.commit() diff --git a/migrations/versions/c3e5c7fe877e_adds_color.py b/migrations/versions/c3e5c7fe877e_adds_color.py new file mode 100644 index 000000000..d69b522bf --- /dev/null +++ b/migrations/versions/c3e5c7fe877e_adds_color.py @@ -0,0 +1,28 @@ +"""adds color + +Revision ID: c3e5c7fe877e +Revises: 927e0daedb50 +Create Date: 2022-12-22 08:39:22.115786 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'c3e5c7fe877e' +down_revision = '927e0daedb50' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('planet', sa.Column('color', sa.String(), nullable=False)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('planet', 'color') + # ### end Alembic commands ### From 2f45c07d94fae61fe7dc35166decda4a86812f05 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 22 Dec 2022 10:19:26 -0800 Subject: [PATCH 21/85] Added attribute livable. change the path to DB. --- app/__init__.py | 4 +-- app/models/planet.py | 4 +-- app/planets_data.csv | 8 +++++ app/routes/planet_routes.py | 5 +++ migrations/versions/C1_add_planet_model.py | 39 ++++++++++++++++++++++ 5 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 migrations/versions/C1_add_planet_model.py diff --git a/app/__init__.py b/app/__init__.py index f861fadf6..3c9c6d15d 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -9,10 +9,10 @@ def create_app(): app = Flask(__name__) app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False - app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql+psycopg2://postgres:postgres@localhost:5432/solar_system_development" + app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql+psycopg2://postgres:postgres@localhost:5432/db_solar_system" db.init_app(app) - migrate.init_app(app, db) + migrate.init_app(app, db, compare_type=True, render_as_batch=True) from app.models.planet import Planet from .routes.planet_routes import planets_bp diff --git a/app/models/planet.py b/app/models/planet.py index 05369fd45..0ba4b5ae2 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -3,8 +3,8 @@ class Planet(db.Model): id = db.Column(db.Integer, primary_key = True, autoincrement = True) name = db.Column(db.String, nullable = False) - #livable = db.Column(db.Boolean, default = False) - number_of_moons = db.Column(db.Integer, nullable = True) + livable = db.Column(db.Boolean, default = False, nullable = True) + number_of_moons = db.Column(db.Integer, default = 0, nullable = False) length_of_year = db.Column(db.Integer, nullable = False) namesake = db.Column(db.String, nullable = False) atmosphere = db.Column(db.String, nullable = False) diff --git a/app/planets_data.csv b/app/planets_data.csv index 02b7142d4..40c0cb374 100644 --- a/app/planets_data.csv +++ b/app/planets_data.csv @@ -6,6 +6,7 @@ "id": 1, "length_of_year": 88, "name": "Mercury", + "livable": false, "namesake": "Roman God Of Speed", "number_of_moons": 0 }, @@ -16,6 +17,7 @@ "id": 3, "length_of_year": 225, "name": "Venus", + "livable": false, "namesake": "Roman Goddess Of Love", "number_of_moons": 0 }, @@ -26,6 +28,7 @@ "id": 4, "length_of_year": 365, "name": "Earth", + "livable": true, "namesake": "The Ground", "number_of_moons": 1 }, @@ -36,6 +39,7 @@ "id": 5, "length_of_year": 687, "name": "Mars", + "livable": false, "namesake": "Roman God Of War", "number_of_moons": 2 }, @@ -46,6 +50,7 @@ "id": 6, "length_of_year": 687, "name": "Jupiter", + "livable": false, "namesake": "King Of The Roman Gods", "number_of_moons": 79 }, @@ -56,6 +61,7 @@ "id": 7, "length_of_year": 10756, "name": "Saturn", + "livable": false, "namesake": "Father Of Jupiter", "number_of_moons": 62 }, @@ -66,6 +72,7 @@ "id": 8, "length_of_year": 30687, "name": "Uranus", + "livable": false, "namesake": "Greek God Of The Sky", "number_of_moons": 27 }, @@ -76,6 +83,7 @@ "id": 9, "length_of_year": 60190, "name": "Neptune", + "livable": false, "namesake": "Roman God Of The Sea", "number_of_moons": 14 } diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 8569b1482..f77baf4fb 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -22,6 +22,7 @@ def validate_planet(planet_id): # Returning the valid JSON if valid input def validate_input(planet_value): if "name" not in planet_value or not isinstance(planet_value["name"], str) \ + or "livable" not in planet_value or not isinstance(planet_value["livable"], bool) \ or "number_of_moons" not in planet_value or not isinstance(planet_value["number_of_moons"], int) \ or "length_of_year" not in planet_value or not isinstance(planet_value["length_of_year"], int) \ or "namesake" not in planet_value or not isinstance(planet_value["namesake"], str) \ @@ -38,6 +39,7 @@ def create_planet(): planet_value = validate_input(request.get_json()) new_planet = Planet( name = planet_value["name"], + livable = planet_value["livable"], number_of_moons = planet_value["number_of_moons"], length_of_year = planet_value["length_of_year"], namesake = planet_value["namesake"], @@ -59,6 +61,7 @@ def get_all_planets(): { "id": planet.id, "name": planet.name, + "livable": planet.livable, "number_of_moons": planet.number_of_moons, "length_of_year": planet.length_of_year, "namesake": planet.namesake, @@ -76,6 +79,7 @@ def get_one_planet(planet_id): return { "id": planet.id, "name": planet.name, + "livable": planet.livable, "number_of_moons": planet.number_of_moons, "length_of_year": planet.length_of_year, "namesake": planet.namesake, @@ -91,6 +95,7 @@ def update_planet(planet_id): request_body = validate_input(request.get_json()) planet.name = request_body["name"], + planet.livable = request_body["livable"], planet.number_of_moons = request_body["number_of_moons"], planet.length_of_year = request_body["length_of_year"], planet.namesake = request_body["namesake"], diff --git a/migrations/versions/C1_add_planet_model.py b/migrations/versions/C1_add_planet_model.py new file mode 100644 index 000000000..86f66e89c --- /dev/null +++ b/migrations/versions/C1_add_planet_model.py @@ -0,0 +1,39 @@ +"""Add Planet model + +Revision ID: C1 +Revises: +Create Date: 2022-12-21 20:25:38.347061 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'C1' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('planet', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('name', sa.String(), nullable=False), + sa.Column('livable', sa.Boolean(), nullable=True), + sa.Column('number_of_moons', sa.Integer(), nullable=False), + sa.Column('length_of_year', sa.Integer(), nullable=False), + sa.Column('namesake', sa.String(), nullable=False), + sa.Column('atmosphere', sa.String(), nullable=False), + sa.Column('diameter', sa.String(), nullable=False), + sa.Column('description', sa.String(), nullable=False), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('planet') + # ### end Alembic commands ### From d4bd163672f1f24a4205c81418a387b29d1e7087 Mon Sep 17 00:00:00 2001 From: annadu Date: Thu, 22 Dec 2022 10:19:46 -0800 Subject: [PATCH 22/85] delete color --- app/models/planet.py | 2 +- app/routes/planet_routes.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/planet.py b/app/models/planet.py index 1d0b432b7..3cd9ee382 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -11,4 +11,4 @@ class Planet(db.Model): atmosphere = db.Column(db.String, nullable = False) diameter = db.Column(db.String, nullable = False) description = db.Column(db.String, nullable = False) - color = db.Column(db.String) \ No newline at end of file + #color = db.Column(db.String) \ No newline at end of file diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index b09b250c4..da4d49b1f 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -68,7 +68,7 @@ def get_all_planets(): "diameter": planet.diameter, "description": planet.description, "livable":planet.livable, - "color":planet.color + #"color":planet.color }) return jsonify(planet_response), 200 @@ -87,7 +87,7 @@ def get_one_planet(planet_id): "diameter": planet.diameter, "description": planet.description, "livable":planet.livable, - "color":planet.color + #"color":planet.color } # Update one planet @@ -104,7 +104,7 @@ def update_planet(planet_id): planet.meter = request_body["diameter"], planet.description = request_body["description"], planet.livable = request_body["livable"], - planet.color= request_body["color"] + #planet.color= request_body["color"] db.session.commit() From e2e32813eec49770ee1733b47bff24c6f41b3272 Mon Sep 17 00:00:00 2001 From: annadu Date: Thu, 22 Dec 2022 11:11:33 -0800 Subject: [PATCH 23/85] not search by name --- app/routes/planet_routes.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index da4d49b1f..671bdbdce 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -44,8 +44,8 @@ def create_planet(): atmosphere = planet_value["atmosphere"], diameter = planet_value["diameter"], description = planet_value["description"], - livable = planet_value["livable"], - color = planet_value["color"]) + livable = planet_value["livable"],) + #color = planet_value["color"]) db.session.add(new_planet) db.session.commit() return make_response(f"Planet {new_planet.name} succesfully created", 201) @@ -54,7 +54,28 @@ def create_planet(): # Return JSON list @planets_bp.route("", methods = ["GET"]) def get_all_planets(): - all_planets = Planet.query.all() + planet_query = Planet.query + planet_name_query = request.args.get("name") + if planet_name_query: + all_planets = planet_query.filter(Planet.name.ilike(f"%{planet_name_query}%")) + + + sort_query = request.args.get("sort") + if sort_query == "desc": + all_planets = planet_query.order_by(Planet.name.desc()).all() + elif sort_query == "asc": + all_planets = planet_query.order_by(Planet.name).all() + + else: + all_planets = planet_query.all() + + + # planet_name_query = request.args.get("name") + # if planet_name_query: + # all_planets = Planet.query.filter(Planet.name.ilike(f"%{planet_name_query}%")) + + + planet_response = [] for planet in all_planets: planet_response.append( From 3c6810e8949184b40082a8d71145171c7ecb5166 Mon Sep 17 00:00:00 2001 From: annadu Date: Thu, 22 Dec 2022 11:23:01 -0800 Subject: [PATCH 24/85] separate work --- app/routes/planet_routes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 671bdbdce..414b74aac 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -66,8 +66,8 @@ def get_all_planets(): elif sort_query == "asc": all_planets = planet_query.order_by(Planet.name).all() - else: - all_planets = planet_query.all() + # else: + # all_planets = planet_query.all() # planet_name_query = request.args.get("name") From 2160c3665af4ec554351c999ef5206aa55d50d26 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 22 Dec 2022 11:32:18 -0800 Subject: [PATCH 25/85] merge conflict solved --- app/routes/planet_routes.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 05159769a..fa6caf7e3 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -45,8 +45,7 @@ def create_planet(): namesake = planet_value["namesake"], atmosphere = planet_value["atmosphere"], diameter = planet_value["diameter"], - description = planet_value["description"], - livable = planet_value["livable"]) + description = planet_value["description"]) db.session.add(new_planet) db.session.commit() return make_response(f"Planet {new_planet.name} succesfully created", 201) @@ -68,8 +67,7 @@ def get_all_planets(): "namesake": planet.namesake, "atmosphere": planet.atmosphere, "diameter": planet.diameter, - "description": planet.description, - "livable":planet.livable + "description": planet.description }) return jsonify(planet_response), 200 @@ -87,8 +85,7 @@ def get_one_planet(planet_id): "namesake": planet.namesake, "atmosphere": planet.atmosphere, "diameter": planet.diameter, - "description": planet.description, - "livable":planet.livable + "description": planet.description } # Update one planet @@ -104,8 +101,7 @@ def update_planet(planet_id): planet.namesake = request_body["namesake"], planet.atmosphere = request_body["atmosphere"], planet.meter = request_body["diameter"], - planet.description = request_body["description"], - planet.livable = request_body["livable"] + planet.description = request_body["description"] db.session.commit() From 966765e273c1e536ced1d6159bd129040522a04b Mon Sep 17 00:00:00 2001 From: annadu Date: Thu, 22 Dec 2022 11:34:17 -0800 Subject: [PATCH 26/85] wave 5 done --- app/routes/planet_routes.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 414b74aac..1a4649506 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -57,14 +57,14 @@ def get_all_planets(): planet_query = Planet.query planet_name_query = request.args.get("name") if planet_name_query: - all_planets = planet_query.filter(Planet.name.ilike(f"%{planet_name_query}%")) + planet_query = planet_query.filter(Planet.name.ilike(f"%{planet_name_query}%")) sort_query = request.args.get("sort") if sort_query == "desc": - all_planets = planet_query.order_by(Planet.name.desc()).all() + planet_query = planet_query.order_by(Planet.name.desc()).all() elif sort_query == "asc": - all_planets = planet_query.order_by(Planet.name).all() + planet_query = planet_query.order_by(Planet.name).all() # else: # all_planets = planet_query.all() @@ -77,7 +77,7 @@ def get_all_planets(): planet_response = [] - for planet in all_planets: + for planet in planet_query: planet_response.append( { "id": planet.id, From 1b8628d54725f0951ba77dedc8e60f33ea439b96 Mon Sep 17 00:00:00 2001 From: annadu Date: Thu, 22 Dec 2022 11:35:38 -0800 Subject: [PATCH 27/85] change method name to get planets_query --- app/routes/planet_routes.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 1a4649506..d82bbdd87 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -53,7 +53,7 @@ def create_planet(): # Get all planets info # Return JSON list @planets_bp.route("", methods = ["GET"]) -def get_all_planets(): +def get_planets_query(): planet_query = Planet.query planet_name_query = request.args.get("name") if planet_name_query: @@ -66,16 +66,7 @@ def get_all_planets(): elif sort_query == "asc": planet_query = planet_query.order_by(Planet.name).all() - # else: - # all_planets = planet_query.all() - - - # planet_name_query = request.args.get("name") - # if planet_name_query: - # all_planets = Planet.query.filter(Planet.name.ilike(f"%{planet_name_query}%")) - - - + planet_response = [] for planet in planet_query: planet_response.append( From ade3c8ffc39151c40ebb915944c3b6381ccc2421 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 22 Dec 2022 11:47:05 -0800 Subject: [PATCH 28/85] two param query worked --- app/routes/planet_routes.py | 39 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 5e77665bd..404d8d4a3 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -45,9 +45,8 @@ def create_planet(): namesake = planet_value["namesake"], atmosphere = planet_value["atmosphere"], diameter = planet_value["diameter"], - description = planet_value["description"], - livable = planet_value["livable"],) - #color = planet_value["color"]) + description = planet_value["description"]) + db.session.add(new_planet) db.session.commit() return make_response(f"Planet {new_planet.name} succesfully created", 201) @@ -55,31 +54,20 @@ def create_planet(): # Get all planets info # Return JSON list @planets_bp.route("", methods = ["GET"]) -def get_all_planets(): +def get_planets_query(): planet_query = Planet.query planet_name_query = request.args.get("name") if planet_name_query: - all_planets = planet_query.filter(Planet.name.ilike(f"%{planet_name_query}%")) - - + planet_query = planet_query.filter(Planet.name.ilike(f"%{planet_name_query}%")) + sort_query = request.args.get("sort") if sort_query == "desc": - all_planets = planet_query.order_by(Planet.name.desc()).all() + planet_query = planet_query.order_by(Planet.name.desc()).all() elif sort_query == "asc": - all_planets = planet_query.order_by(Planet.name).all() - - # else: - # all_planets = planet_query.all() - - - # planet_name_query = request.args.get("name") - # if planet_name_query: - # all_planets = Planet.query.filter(Planet.name.ilike(f"%{planet_name_query}%")) - - - + planet_query = planet_query.order_by(Planet.name).all() + planet_response = [] - for planet in all_planets: + for planet in planet_query: planet_response.append( { "id": planet.id, @@ -90,8 +78,7 @@ def get_all_planets(): "namesake": planet.namesake, "atmosphere": planet.atmosphere, "diameter": planet.diameter, - "description": planet.description, - "livable":planet.livable + "description": planet.description }) return jsonify(planet_response), 200 @@ -109,8 +96,7 @@ def get_one_planet(planet_id): "namesake": planet.namesake, "atmosphere": planet.atmosphere, "diameter": planet.diameter, - "description": planet.description, - "livable":planet.livable + "description": planet.description } # Update one planet @@ -126,8 +112,7 @@ def update_planet(planet_id): planet.namesake = request_body["namesake"], planet.atmosphere = request_body["atmosphere"], planet.meter = request_body["diameter"], - planet.description = request_body["description"], - planet.livable = request_body["livable"] + planet.description = request_body["description"] db.session.commit() From b5f51527055ed46d708800b73e1c739e3b5ff67b Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 22 Dec 2022 15:08:56 -0800 Subject: [PATCH 29/85] add filtering by livable --- app/routes/planet_routes.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 8f9d74755..95322af77 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -55,17 +55,27 @@ def create_planet(): @planets_bp.route("", methods = ["GET"]) def get_planets_query(): planet_query = Planet.query + # Filtering by name (return all records whitch name contains planet_name_query) planet_name_query = request.args.get("name") if planet_name_query: planet_query = planet_query.filter(Planet.name.ilike(f"%{planet_name_query}%")) + # Filtering by livable or not + planet_livable_query = request.args.get("livable") + if planet_livable_query: + planet_query = planet_query.filter_by(livable = planet_livable_query) + # Sorting by name sort_query = request.args.get("sort") if sort_query == "desc": planet_query = planet_query.order_by(Planet.name.desc()).all() elif sort_query == "asc": planet_query = planet_query.order_by(Planet.name).all() + # Sorting by number_of_moons + + # Sorting by length_of_year + planet_response = [] for planet in planet_query: planet_response.append( From 7d30d751c7ad54b75ad97b010240537330ee3f6c Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 22 Dec 2022 15:29:48 -0800 Subject: [PATCH 30/85] add sorting by additional parameters --- app/models/planet.py | 2 +- app/routes/planet_routes.py | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/app/models/planet.py b/app/models/planet.py index 079273c4f..2abdcf931 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -4,7 +4,7 @@ class Planet(db.Model): id = db.Column(db.Integer, primary_key = True, autoincrement = True) name = db.Column(db.String, nullable = False) - livable = db.Column(db.Boolean, default = False) + livable = db.Column(db.Boolean, default = False, nullable = True) number_of_moons = db.Column(db.Integer, nullable = True) length_of_year = db.Column(db.Integer, nullable = False) namesake = db.Column(db.String, nullable = False) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 95322af77..ede2105cc 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -66,15 +66,25 @@ def get_planets_query(): planet_query = planet_query.filter_by(livable = planet_livable_query) # Sorting by name - sort_query = request.args.get("sort") - if sort_query == "desc": + sort_by_name_query = request.args.get("sort_by_name") + if sort_by_name_query == "desc": planet_query = planet_query.order_by(Planet.name.desc()).all() - elif sort_query == "asc": + elif sort_by_name_query == "asc": planet_query = planet_query.order_by(Planet.name).all() # Sorting by number_of_moons + sort_by_moons_query = request.args.get("sort_by_number_of_moons") + if sort_by_moons_query == "desc": + planet_query = planet_query.order_by(Planet.number_of_moons.desc()).all() + elif sort_by_moons_query == "asc": + planet_query = planet_query.order_by(Planet.number_of_moons).all() # Sorting by length_of_year + sort_lenth_of_year_query = request.args.get("sort_by_length_of_year") + if sort_lenth_of_year_query == "desc": + planet_query = planet_query.order_by(Planet.length_of_year.desc()).all() + elif sort_lenth_of_year_query == "asc": + planet_query = planet_query.order_by(Planet.length_of_year).all() planet_response = [] for planet in planet_query: From f4c755593d884366189f9fa7037837da76f1f1cf Mon Sep 17 00:00:00 2001 From: annadu Date: Thu, 22 Dec 2022 17:57:38 -0800 Subject: [PATCH 31/85] modify color --- app/__init__.py | 8 +++++--- app/models/planet.py | 2 +- app/routes/planet_routes.py | 26 +++++++++++++++++++++----- requirements.txt | 2 +- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index a54959aac..bbb91afc1 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -12,12 +12,14 @@ def create_app(): app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://postgres:postgres@localhost:5432/solar_system_development' - db.init_app(app) - migrate.init_app(app, db) + # db.init_app(app) + # migrate.init_app(app, db) from app.models.planet import Planet + db.init_app(app) + migrate.init_app(app, db) - from .routes.planet_routes import planets_bp + from app.routes.planet_routes import planets_bp app.register_blueprint(planets_bp) return app \ No newline at end of file diff --git a/app/models/planet.py b/app/models/planet.py index 3cd9ee382..d789b2264 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -11,4 +11,4 @@ class Planet(db.Model): atmosphere = db.Column(db.String, nullable = False) diameter = db.Column(db.String, nullable = False) description = db.Column(db.String, nullable = False) - #color = db.Column(db.String) \ No newline at end of file + color = db.Column(db.String,nullable = True) \ No newline at end of file diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index d82bbdd87..2fa797960 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -56,17 +56,33 @@ def create_planet(): def get_planets_query(): planet_query = Planet.query planet_name_query = request.args.get("name") + if planet_name_query: planet_query = planet_query.filter(Planet.name.ilike(f"%{planet_name_query}%")) + + planet_livable_query = request.args.get("livable") + if planet_livable_query: + planet_query = planet_query.filter_by(livable = planet_livable_query) + - - sort_query = request.args.get("sort") - if sort_query == "desc": + sort_by_name_query = request.args.get("sort_by_name") + if sort_by_name_query == "desc": planet_query = planet_query.order_by(Planet.name.desc()).all() - elif sort_query == "asc": + elif sort_by_name_query == "asc": planet_query = planet_query.order_by(Planet.name).all() - + sort_by_number_of_moons_query = request.args.get("sort_by_number_of_moons") + if sort_by_number_of_moons_query == "desc": + planet_query = planet_query.order_by(Planet.number_of_moons.desc()).all() + elif sort_by_number_of_moons_query == "asc": + planet_query = planet_query.order_by(Planet.number_of_moons).all() + + sort_by_length_of_year_query = request.args.get("sort_by_length_of_year") + if sort_by_length_of_year_query == "desc": + planet_query = planet_query.order_by(Planet.length_of_year.desc()).all() + elif sort_by_length_of_year_query == "asc": + planet_query = planet_query.order_by(Planet.length_of_year).all() + planet_response = [] for planet in planet_query: planet_response.append( diff --git a/requirements.txt b/requirements.txt index d93ba05c9..fba2b3e38 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ blinker==1.4 certifi==2020.12.5 chardet==4.0.0 click==7.1.2 -Flask==2.1.0 +Flask==1.1.2 Flask-Migrate==2.6.0 Flask-SQLAlchemy==2.4.4 idna==2.10 From 1810448c8041189e3022a05b226763b9ac71f42b Mon Sep 17 00:00:00 2001 From: annadu Date: Thu, 22 Dec 2022 18:35:31 -0800 Subject: [PATCH 32/85] wave 5 done --- app/planets_data.csv | 8 +++++ migrations/versions/C1_add_planet_model.py | 39 ++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 migrations/versions/C1_add_planet_model.py diff --git a/app/planets_data.csv b/app/planets_data.csv index 02b7142d4..40c0cb374 100644 --- a/app/planets_data.csv +++ b/app/planets_data.csv @@ -6,6 +6,7 @@ "id": 1, "length_of_year": 88, "name": "Mercury", + "livable": false, "namesake": "Roman God Of Speed", "number_of_moons": 0 }, @@ -16,6 +17,7 @@ "id": 3, "length_of_year": 225, "name": "Venus", + "livable": false, "namesake": "Roman Goddess Of Love", "number_of_moons": 0 }, @@ -26,6 +28,7 @@ "id": 4, "length_of_year": 365, "name": "Earth", + "livable": true, "namesake": "The Ground", "number_of_moons": 1 }, @@ -36,6 +39,7 @@ "id": 5, "length_of_year": 687, "name": "Mars", + "livable": false, "namesake": "Roman God Of War", "number_of_moons": 2 }, @@ -46,6 +50,7 @@ "id": 6, "length_of_year": 687, "name": "Jupiter", + "livable": false, "namesake": "King Of The Roman Gods", "number_of_moons": 79 }, @@ -56,6 +61,7 @@ "id": 7, "length_of_year": 10756, "name": "Saturn", + "livable": false, "namesake": "Father Of Jupiter", "number_of_moons": 62 }, @@ -66,6 +72,7 @@ "id": 8, "length_of_year": 30687, "name": "Uranus", + "livable": false, "namesake": "Greek God Of The Sky", "number_of_moons": 27 }, @@ -76,6 +83,7 @@ "id": 9, "length_of_year": 60190, "name": "Neptune", + "livable": false, "namesake": "Roman God Of The Sea", "number_of_moons": 14 } diff --git a/migrations/versions/C1_add_planet_model.py b/migrations/versions/C1_add_planet_model.py new file mode 100644 index 000000000..86f66e89c --- /dev/null +++ b/migrations/versions/C1_add_planet_model.py @@ -0,0 +1,39 @@ +"""Add Planet model + +Revision ID: C1 +Revises: +Create Date: 2022-12-21 20:25:38.347061 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'C1' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('planet', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('name', sa.String(), nullable=False), + sa.Column('livable', sa.Boolean(), nullable=True), + sa.Column('number_of_moons', sa.Integer(), nullable=False), + sa.Column('length_of_year', sa.Integer(), nullable=False), + sa.Column('namesake', sa.String(), nullable=False), + sa.Column('atmosphere', sa.String(), nullable=False), + sa.Column('diameter', sa.String(), nullable=False), + sa.Column('description', sa.String(), nullable=False), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('planet') + # ### end Alembic commands ### From 295d14da6985e85ea7e52516c36abb482ae3be79 Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 12:09:17 -0800 Subject: [PATCH 33/85] change some column --- app/models/planet.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/models/planet.py b/app/models/planet.py index a2fa632ce..9d7d244cc 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -4,11 +4,11 @@ class Planet(db.Model): id = db.Column(db.Integer, primary_key = True, autoincrement = True) name = db.Column(db.String, nullable = False) - livable = db.Column(db.Boolean, default = False, nullable = True) - number_of_moons = db.Column(db.Integer, nullable = True) + #livable = db.Column(db.Boolean, default = False, nullable = True) + #number_of_moons = db.Column(db.Integer, nullable = True) length_of_year = db.Column(db.Integer, nullable = False) - namesake = db.Column(db.String, nullable = False) - atmosphere = db.Column(db.String, nullable = False) - diameter = db.Column(db.String, nullable = False) + #namesake = db.Column(db.String, nullable = False) + #atmosphere = db.Column(db.String, nullable = False) + #diameter = db.Column(db.String, nullable = False) description = db.Column(db.String, nullable = False) - #color = db.Column(db.String, default = False) + \ No newline at end of file From 26f571b46b2a4d5592e606c44289a05769d13cfb Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 12:34:17 -0800 Subject: [PATCH 34/85] delete wrong version --- migrations/versions/C1_add_planet_model.py | 39 ------------------- .../versions/c3e5c7fe877e_adds_color.py | 28 ------------- 2 files changed, 67 deletions(-) delete mode 100644 migrations/versions/C1_add_planet_model.py delete mode 100644 migrations/versions/c3e5c7fe877e_adds_color.py diff --git a/migrations/versions/C1_add_planet_model.py b/migrations/versions/C1_add_planet_model.py deleted file mode 100644 index 86f66e89c..000000000 --- a/migrations/versions/C1_add_planet_model.py +++ /dev/null @@ -1,39 +0,0 @@ -"""Add Planet model - -Revision ID: C1 -Revises: -Create Date: 2022-12-21 20:25:38.347061 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'C1' -down_revision = None -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('planet', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('name', sa.String(), nullable=False), - sa.Column('livable', sa.Boolean(), nullable=True), - sa.Column('number_of_moons', sa.Integer(), nullable=False), - sa.Column('length_of_year', sa.Integer(), nullable=False), - sa.Column('namesake', sa.String(), nullable=False), - sa.Column('atmosphere', sa.String(), nullable=False), - sa.Column('diameter', sa.String(), nullable=False), - sa.Column('description', sa.String(), nullable=False), - sa.PrimaryKeyConstraint('id') - ) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('planet') - # ### end Alembic commands ### diff --git a/migrations/versions/c3e5c7fe877e_adds_color.py b/migrations/versions/c3e5c7fe877e_adds_color.py deleted file mode 100644 index d69b522bf..000000000 --- a/migrations/versions/c3e5c7fe877e_adds_color.py +++ /dev/null @@ -1,28 +0,0 @@ -"""adds color - -Revision ID: c3e5c7fe877e -Revises: 927e0daedb50 -Create Date: 2022-12-22 08:39:22.115786 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'c3e5c7fe877e' -down_revision = '927e0daedb50' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('planet', sa.Column('color', sa.String(), nullable=False)) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('planet', 'color') - # ### end Alembic commands ### From a4b72a0fbf9c3906365ed80c8fd9ee8459d29100 Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 12:47:05 -0800 Subject: [PATCH 35/85] delete some column --- .../60ee1bf3a6d7_delete_some_column.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 migrations/versions/60ee1bf3a6d7_delete_some_column.py diff --git a/migrations/versions/60ee1bf3a6d7_delete_some_column.py b/migrations/versions/60ee1bf3a6d7_delete_some_column.py new file mode 100644 index 000000000..f9f22a6c4 --- /dev/null +++ b/migrations/versions/60ee1bf3a6d7_delete_some_column.py @@ -0,0 +1,36 @@ +"""delete some column + +Revision ID: 60ee1bf3a6d7 +Revises: 927e0daedb50 +Create Date: 2023-01-03 12:32:11.382959 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '60ee1bf3a6d7' +down_revision = '927e0daedb50' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('planet', 'namesake') + op.drop_column('planet', 'diameter') + op.drop_column('planet', 'livable') + op.drop_column('planet', 'number_of_moons') + op.drop_column('planet', 'atmosphere') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('planet', sa.Column('atmosphere', sa.VARCHAR(), autoincrement=False, nullable=False)) + op.add_column('planet', sa.Column('number_of_moons', sa.INTEGER(), autoincrement=False, nullable=True)) + op.add_column('planet', sa.Column('livable', sa.BOOLEAN(), autoincrement=False, nullable=True)) + op.add_column('planet', sa.Column('diameter', sa.VARCHAR(), autoincrement=False, nullable=False)) + op.add_column('planet', sa.Column('namesake', sa.VARCHAR(), autoincrement=False, nullable=False)) + # ### end Alembic commands ### From ff76b056128804d188b138e937e34756c2e68fd2 Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 12:47:44 -0800 Subject: [PATCH 36/85] delete class Planet some attributes --- app/models/planet.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/models/planet.py b/app/models/planet.py index 9d7d244cc..f55dbfa5c 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -4,11 +4,6 @@ class Planet(db.Model): id = db.Column(db.Integer, primary_key = True, autoincrement = True) name = db.Column(db.String, nullable = False) - #livable = db.Column(db.Boolean, default = False, nullable = True) - #number_of_moons = db.Column(db.Integer, nullable = True) - length_of_year = db.Column(db.Integer, nullable = False) - #namesake = db.Column(db.String, nullable = False) - #atmosphere = db.Column(db.String, nullable = False) - #diameter = db.Column(db.String, nullable = False) + length_of_year = db.Column(db.Integer, nullable = False) description = db.Column(db.String, nullable = False) \ No newline at end of file From fca60562de31090c524a63e7a260b7c9c8df8520 Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 12:53:03 -0800 Subject: [PATCH 37/85] add tests/test_routes.py --- tests/test_routes.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/test_routes.py diff --git a/tests/test_routes.py b/tests/test_routes.py new file mode 100644 index 000000000..e69de29bb From 1b474f335d9fbf10b7285b45d02505ffd3eeda10 Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 12:53:15 -0800 Subject: [PATCH 38/85] tests/conftest.py --- tests/conftest.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/conftest.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..e69de29bb From 56306efd83a6424e87cf94a5796a648f834eeffd Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 12:53:25 -0800 Subject: [PATCH 39/85] tests/__init__.py --- tests/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/__init__.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb From 3653d9f38f5e8642201ad563c2c5100c7937d8e0 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Tue, 3 Jan 2023 12:53:33 -0800 Subject: [PATCH 40/85] Update the planet model, create .env file --- app/__init__.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index a17a94c07..d4d1ab513 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -10,14 +10,16 @@ def create_app(): app = Flask(__name__) app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False - app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql+psycopg2://postgres:postgres@localhost:5432/solar_system_development" + app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql+psycopg2://postgres:postgres@localhost:5432/db_solar_system" - from app.models.planet import Planet + db.init_app(app) migrate.init_app(app, db) + + from app.models.planet import Planet - from app.routes.planet_routes import planets_bp + from .routes.planet_routes import planets_bp app.register_blueprint(planets_bp) return app \ No newline at end of file From 8a8db01eb14d92e83497ed5b015472f58677228a Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Tue, 3 Jan 2023 12:54:00 -0800 Subject: [PATCH 41/85] update planet model --- app/__init__.py | 13 +++- app/models/planet.py | 6 -- app/planets_data.csv | 64 +++---------------- app/routes/planet_routes.py | 36 ----------- ...l.py => 00194cde28bc_adds_planet_model.py} | 12 ++-- .../1aeb2d9c2e75_update_planet_model.py | 28 -------- ...daedb50_update_planet_model_add_livable.py | 28 -------- ...c913d5e2a_update_planet_model_with_kate.py | 38 ----------- migrations/versions/C1_add_planet_model.py | 39 ----------- .../versions/c3e5c7fe877e_adds_color.py | 28 -------- 10 files changed, 24 insertions(+), 268 deletions(-) rename migrations/versions/{121486141f79_adds_planet_model.py => 00194cde28bc_adds_planet_model.py} (69%) delete mode 100644 migrations/versions/1aeb2d9c2e75_update_planet_model.py delete mode 100644 migrations/versions/927e0daedb50_update_planet_model_add_livable.py delete mode 100644 migrations/versions/953c913d5e2a_update_planet_model_with_kate.py delete mode 100644 migrations/versions/C1_add_planet_model.py delete mode 100644 migrations/versions/c3e5c7fe877e_adds_color.py diff --git a/app/__init__.py b/app/__init__.py index d4d1ab513..458b11c99 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,16 +1,23 @@ from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate +from dotenv import load_dotenv +import os db = SQLAlchemy() migrate = Migrate() +load_dotenv() - -def create_app(): +def create_app(test_config = None): app = Flask(__name__) app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False - app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql+psycopg2://postgres:postgres@localhost:5432/db_solar_system" + + if test_config: + app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("SQLALCHEMY_TEST_DATABASE_URI") + app.config["Testing"] = True + else: + app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("SQLALCHEMY_DATABASE_URI") from app.models.planet import Planet diff --git a/app/models/planet.py b/app/models/planet.py index a2fa632ce..f2019f828 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -4,11 +4,5 @@ class Planet(db.Model): id = db.Column(db.Integer, primary_key = True, autoincrement = True) name = db.Column(db.String, nullable = False) - livable = db.Column(db.Boolean, default = False, nullable = True) - number_of_moons = db.Column(db.Integer, nullable = True) length_of_year = db.Column(db.Integer, nullable = False) - namesake = db.Column(db.String, nullable = False) - atmosphere = db.Column(db.String, nullable = False) - diameter = db.Column(db.String, nullable = False) description = db.Column(db.String, nullable = False) - #color = db.Column(db.String, default = False) diff --git a/app/planets_data.csv b/app/planets_data.csv index 40c0cb374..34df10aff 100644 --- a/app/planets_data.csv +++ b/app/planets_data.csv @@ -1,90 +1,42 @@ [ { - "atmosphere": "minimal", "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", - "diameter": "0.383", - "id": 1, "length_of_year": 88, - "name": "Mercury", - "livable": false, - "namesake": "Roman God Of Speed", - "number_of_moons": 0 + "name": "Mercury" }, { - "atmosphere": "CO2, N2", "description": "Venus spins slowly in the opposite direction from most planets.", - "diameter": "0.949", - "id": 3, "length_of_year": 225, - "name": "Venus", - "livable": false, - "namesake": "Roman Goddess Of Love", - "number_of_moons": 0 + "name": "Venus" }, { - "atmosphere": "N2, O2, Ar", "description": "Earth — our home planet.", - "diameter": "1.000", - "id": 4, "length_of_year": 365, - "name": "Earth", - "livable": true, - "namesake": "The Ground", - "number_of_moons": 1 + "name": "Earth" }, { - "atmosphere": "CO2, N2, Ar", "description": "Mars is a dusty, cold, desert world with a very thin atmosphere.", - "diameter": "0.532", - "id": 5, "length_of_year": 687, - "name": "Mars", - "livable": false, - "namesake": "Roman God Of War", - "number_of_moons": 2 + "name": "Mars" }, { - "atmosphere": "H2, He", "description": "Jupiter is more than twice as massive than the other planets of our solar system combined.", - "diameter": "11.209", - "id": 6, "length_of_year": 687, - "name": "Jupiter", - "livable": false, - "namesake": "King Of The Roman Gods", - "number_of_moons": 79 + "name": "Jupiter" }, { - "atmosphere": "H2, He", "description": "Adorned with a dazzling, complex system of icy rings, Saturn is unique in our solar system.", - "diameter": "9.449", - "id": 7, "length_of_year": 10756, - "name": "Saturn", - "livable": false, - "namesake": "Father Of Jupiter", - "number_of_moons": 62 + "name": "Saturn" }, { - "atmosphere": "H2, He, CH4", "description": "Uranus—seventh planet from the Sun—rotates at a nearly 90-degree angle from the plane of its orbit.", - "diameter": "4.007", - "id": 8, "length_of_year": 30687, - "name": "Uranus", - "livable": false, - "namesake": "Greek God Of The Sky", - "number_of_moons": 27 + "name": "Uranus" }, { - "atmosphere": "H2, He, CH4", "description": "Neptune—the eighth and most distant major planet orbiting our Sun—is dark, cold and whipped by supersonic winds.", - "diameter": "3.883", - "id": 9, "length_of_year": 60190, - "name": "Neptune", - "livable": false, - "namesake": "Roman God Of The Sea", - "number_of_moons": 14 + "name": "Neptune" } ] \ No newline at end of file diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index eeb2fa16c..0a22fe6f5 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -21,12 +21,7 @@ def validate_planet(planet_id): # Returning the valid JSON if valid input def validate_input(planet_value): if "name" not in planet_value or not isinstance(planet_value["name"], str) \ - or "livable" not in planet_value or not isinstance(planet_value["livable"], bool) \ - or "number_of_moons" not in planet_value or not isinstance(planet_value["number_of_moons"], int) \ or "length_of_year" not in planet_value or not isinstance(planet_value["length_of_year"], int) \ - or "namesake" not in planet_value or not isinstance(planet_value["namesake"], str) \ - or "atmosphere" not in planet_value or not isinstance(planet_value["atmosphere"], str) \ - or "diameter" not in planet_value or not isinstance(planet_value["diameter"], str) \ or "description" not in planet_value or not isinstance(planet_value["description"], str): return abort(make_response(f"Invalid request", 400)) return planet_value @@ -38,12 +33,7 @@ def create_planet(): planet_value = validate_input(request.get_json()) new_planet = Planet( name = planet_value["name"], - livable = planet_value["livable"], - number_of_moons = planet_value["number_of_moons"], length_of_year = planet_value["length_of_year"], - namesake = planet_value["namesake"], - atmosphere = planet_value["atmosphere"], - diameter = planet_value["diameter"], description = planet_value["description"]) db.session.add(new_planet) @@ -61,23 +51,12 @@ def get_planets_query(): if planet_name_query: planet_query = planet_query.filter(Planet.name.ilike(f"%{planet_name_query}%")) - planet_livable_query = request.args.get("livable") - if planet_livable_query: - planet_query = planet_query.filter_by(livable = planet_livable_query) - - sort_by_name_query = request.args.get("sort_by_name") if sort_by_name_query == "desc": planet_query = planet_query.order_by(Planet.name.desc()).all() elif sort_by_name_query == "asc": planet_query = planet_query.order_by(Planet.name).all() - sort_by_number_of_moons_query = request.args.get("sort_by_number_of_moons") - if sort_by_number_of_moons_query == "desc": - planet_query = planet_query.order_by(Planet.number_of_moons.desc()).all() - elif sort_by_number_of_moons_query == "asc": - planet_query = planet_query.order_by(Planet.number_of_moons).all() - sort_by_length_of_year_query = request.args.get("sort_by_length_of_year") if sort_by_length_of_year_query == "desc": planet_query = planet_query.order_by(Planet.length_of_year.desc()).all() @@ -90,12 +69,7 @@ def get_planets_query(): { "id": planet.id, "name": planet.name, - "livable": planet.livable, - "number_of_moons": planet.number_of_moons, "length_of_year": planet.length_of_year, - "namesake": planet.namesake, - "atmosphere": planet.atmosphere, - "diameter": planet.diameter, "description": planet.description }) return jsonify(planet_response), 200 @@ -108,12 +82,7 @@ def get_one_planet(planet_id): return { "id": planet.id, "name": planet.name, - "livable": planet.livable, - "number_of_moons": planet.number_of_moons, "length_of_year": planet.length_of_year, - "namesake": planet.namesake, - "atmosphere": planet.atmosphere, - "diameter": planet.diameter, "description": planet.description } @@ -124,12 +93,7 @@ def update_planet(planet_id): request_body = validate_input(request.get_json()) planet.name = request_body["name"], - planet.livable = request_body["livable"], - planet.number_of_moons = request_body["number_of_moons"], planet.length_of_year = request_body["length_of_year"], - planet.namesake = request_body["namesake"], - planet.atmosphere = request_body["atmosphere"], - planet.meter = request_body["diameter"], planet.description = request_body["description"] db.session.commit() diff --git a/migrations/versions/121486141f79_adds_planet_model.py b/migrations/versions/00194cde28bc_adds_planet_model.py similarity index 69% rename from migrations/versions/121486141f79_adds_planet_model.py rename to migrations/versions/00194cde28bc_adds_planet_model.py index 15b4d5a86..0fd109ab6 100644 --- a/migrations/versions/121486141f79_adds_planet_model.py +++ b/migrations/versions/00194cde28bc_adds_planet_model.py @@ -1,8 +1,8 @@ """adds Planet model -Revision ID: 121486141f79 +Revision ID: 00194cde28bc Revises: -Create Date: 2022-12-20 19:05:14.734348 +Create Date: 2023-01-03 12:33:11.301835 """ from alembic import op @@ -10,7 +10,7 @@ # revision identifiers, used by Alembic. -revision = '121486141f79' +revision = '00194cde28bc' down_revision = None branch_labels = None depends_on = None @@ -20,9 +20,9 @@ def upgrade(): # ### commands auto generated by Alembic - please adjust! ### op.create_table('planet', sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('name', sa.String(), nullable=True), - sa.Column('description', sa.Text(), nullable=True), - sa.Column('diameter', sa.Integer(), nullable=True), + sa.Column('name', sa.String(), nullable=False), + sa.Column('length_of_year', sa.Integer(), nullable=False), + sa.Column('description', sa.String(), nullable=False), sa.PrimaryKeyConstraint('id') ) # ### end Alembic commands ### diff --git a/migrations/versions/1aeb2d9c2e75_update_planet_model.py b/migrations/versions/1aeb2d9c2e75_update_planet_model.py deleted file mode 100644 index 7cc8e1365..000000000 --- a/migrations/versions/1aeb2d9c2e75_update_planet_model.py +++ /dev/null @@ -1,28 +0,0 @@ -"""update Planet model - -Revision ID: 1aeb2d9c2e75 -Revises: 121486141f79 -Create Date: 2022-12-20 19:52:02.304999 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = '1aeb2d9c2e75' -down_revision = '121486141f79' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('planet', sa.Column('atmosphere', sa.String(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('planet', 'atmosphere') - # ### end Alembic commands ### diff --git a/migrations/versions/927e0daedb50_update_planet_model_add_livable.py b/migrations/versions/927e0daedb50_update_planet_model_add_livable.py deleted file mode 100644 index 003d7deae..000000000 --- a/migrations/versions/927e0daedb50_update_planet_model_add_livable.py +++ /dev/null @@ -1,28 +0,0 @@ -"""update planet model add livable - -Revision ID: 927e0daedb50 -Revises: 953c913d5e2a -Create Date: 2022-12-21 12:45:10.302200 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = '927e0daedb50' -down_revision = '953c913d5e2a' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('planet', sa.Column('livable', sa.Boolean(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('planet', 'livable') - # ### end Alembic commands ### diff --git a/migrations/versions/953c913d5e2a_update_planet_model_with_kate.py b/migrations/versions/953c913d5e2a_update_planet_model_with_kate.py deleted file mode 100644 index a62f684b6..000000000 --- a/migrations/versions/953c913d5e2a_update_planet_model_with_kate.py +++ /dev/null @@ -1,38 +0,0 @@ -"""update planet model with kate - -Revision ID: 953c913d5e2a -Revises: 1aeb2d9c2e75 -Create Date: 2022-12-21 12:40:21.897814 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = '953c913d5e2a' -down_revision = '1aeb2d9c2e75' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('planet', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('name', sa.String(), nullable=False), - sa.Column('number_of_moons', sa.Integer(), nullable=True), - sa.Column('length_of_year', sa.Integer(), nullable=False), - sa.Column('namesake', sa.String(), nullable=False), - sa.Column('atmosphere', sa.String(), nullable=False), - sa.Column('diameter', sa.String(), nullable=False), - sa.Column('description', sa.String(), nullable=False), - sa.PrimaryKeyConstraint('id') - ) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('planet') - # ### end Alembic commands ### diff --git a/migrations/versions/C1_add_planet_model.py b/migrations/versions/C1_add_planet_model.py deleted file mode 100644 index 86f66e89c..000000000 --- a/migrations/versions/C1_add_planet_model.py +++ /dev/null @@ -1,39 +0,0 @@ -"""Add Planet model - -Revision ID: C1 -Revises: -Create Date: 2022-12-21 20:25:38.347061 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'C1' -down_revision = None -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('planet', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('name', sa.String(), nullable=False), - sa.Column('livable', sa.Boolean(), nullable=True), - sa.Column('number_of_moons', sa.Integer(), nullable=False), - sa.Column('length_of_year', sa.Integer(), nullable=False), - sa.Column('namesake', sa.String(), nullable=False), - sa.Column('atmosphere', sa.String(), nullable=False), - sa.Column('diameter', sa.String(), nullable=False), - sa.Column('description', sa.String(), nullable=False), - sa.PrimaryKeyConstraint('id') - ) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('planet') - # ### end Alembic commands ### diff --git a/migrations/versions/c3e5c7fe877e_adds_color.py b/migrations/versions/c3e5c7fe877e_adds_color.py deleted file mode 100644 index d69b522bf..000000000 --- a/migrations/versions/c3e5c7fe877e_adds_color.py +++ /dev/null @@ -1,28 +0,0 @@ -"""adds color - -Revision ID: c3e5c7fe877e -Revises: 927e0daedb50 -Create Date: 2022-12-22 08:39:22.115786 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'c3e5c7fe877e' -down_revision = '927e0daedb50' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('planet', sa.Column('color', sa.String(), nullable=False)) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('planet', 'color') - # ### end Alembic commands ### From 680ab2a3be2476d587a52bbc9b36c62d2b369a85 Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 12:55:02 -0800 Subject: [PATCH 42/85] finish config test environment --- app/__init__.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index a17a94c07..07a0d6814 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,17 +1,24 @@ from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate +from dotenv import load_dotenv +import os + db = SQLAlchemy() migrate = Migrate() +load_dotenv() -def create_app(): +def create_app(test_config=None): app = Flask(__name__) - app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False - app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql+psycopg2://postgres:postgres@localhost:5432/solar_system_development" - + + if not test_config: + app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI + else: + app.config["TESTING"] = True + app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_TEST_DATABASE_URI from app.models.planet import Planet db.init_app(app) From 067596f303af88b45146749c70527b9b160d6d3b Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 12:59:58 -0800 Subject: [PATCH 43/85] add os.environ to read variable SQLALCHEMY_DATABASE_URI --- app/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 07a0d6814..dfb5d1d64 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -15,10 +15,10 @@ def create_app(test_config=None): app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False if not test_config: - app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI + app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("SQLALCHEMY_DATABASE_URI") else: app.config["TESTING"] = True - app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_TEST_DATABASE_URI + app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("SQLALCHEMY_TEST_DATABASE_URI") from app.models.planet import Planet db.init_app(app) From c4430fe62a71634a2dc5b5444b3da1e0ac1b31ee Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Tue, 3 Jan 2023 15:47:54 -0800 Subject: [PATCH 44/85] Add test_create_planet_valid_request. --- app/routes/planet_routes.py | 2 +- app/planets_data.csv => planets_data.csv | 0 tests/__init__.py | 0 tests/conftest.py | 54 ++++++++++++++++++++++++ tests/test_planet_routes.py | 12 ++++++ 5 files changed, 67 insertions(+), 1 deletion(-) rename app/planets_data.csv => planets_data.csv (100%) create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/test_planet_routes.py diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 0a22fe6f5..9dcef50ac 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -38,7 +38,7 @@ def create_planet(): db.session.add(new_planet) db.session.commit() - return make_response(f"Planet {new_planet.name} succesfully created", 201) + return make_response(jsonify(f"Planet {new_planet.name} successfully created"), 201) # Get all planets info # Return JSON list diff --git a/app/planets_data.csv b/planets_data.csv similarity index 100% rename from app/planets_data.csv rename to planets_data.csv diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..74aa1fc4f --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,54 @@ +import pytest +from app import create_app, db +from flask.signals import request_finished +from app.models.planet import Planet + +@pytest.fixture +def app(): + app = create_app(test_config=True) + + @request_finished.connect_via(app) + def expire_session(sender, response, **extra): + db.session.remove() + + with app.app_context(): + db.create_all() + yield app + + with app.app_context(): + db.drop_all() + +@pytest.fixture +def client(app): + return app.test_client() + + +@pytest.fixture +def one_planet(app): + planet = Planet( + name = "Mercury", + description = "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + length_of_year = 88) + + db.session.add(planet) + db.session.commit() + db.session.refresh(planet, ["id"]) + return planet + +@pytest.fixture +def three_planets(app): + planet_mercury = Planet( + name = "Mercury", + description = "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + length_of_year = 88) + planet_venus = Planet( + name = "Venus", + description = "Venus spins slowly in the opposite direction from most planets.", + length_of_year = 225) + planet_earth = Planet( + name = "Earth", + description = "Earth — our home planet.", + length_of_year = 365) + + db.session.add_all([planet_mercury, planet_venus, planet_earth]) + db.session.commit() \ No newline at end of file diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py new file mode 100644 index 000000000..10ca7eb96 --- /dev/null +++ b/tests/test_planet_routes.py @@ -0,0 +1,12 @@ +def test_create_planet_valid_request(client): + # Act + response = client.post("/planets", json = { + "description": "Mars is a dusty, cold, desert world with a very thin atmosphere.", + "length_of_year": 687, + "name": "Mars" + }) + response_body = response.get_json() + + # Assert + assert response.status_code == 201 + assert response_body == "Planet Mars successfully created" \ No newline at end of file From 1ba96d17c15051edb945c00d33efce0c7b3ba55a Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Tue, 3 Jan 2023 16:38:58 -0800 Subject: [PATCH 45/85] add edge cases to test create_planet --- app/routes/planet_routes.py | 14 +++++++--- tests/conftest.py | 2 +- tests/test_planet_routes.py | 52 +++++++++++++++++++++++++++++++++++-- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 9dcef50ac..afe83164b 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -20,10 +20,16 @@ def validate_planet(planet_id): # Validating the user input to create or update the table planet # Returning the valid JSON if valid input def validate_input(planet_value): - if "name" not in planet_value or not isinstance(planet_value["name"], str) \ - or "length_of_year" not in planet_value or not isinstance(planet_value["length_of_year"], int) \ - or "description" not in planet_value or not isinstance(planet_value["description"], str): - return abort(make_response(f"Invalid request", 400)) + if "name" not in planet_value \ + or not isinstance(planet_value["name"], str) \ + or planet_value["name"] == '' \ + or "length_of_year" not in planet_value \ + or not isinstance(planet_value["length_of_year"], int) \ + or planet_value["length_of_year"] <=0 \ + or "description" not in planet_value \ + or not isinstance(planet_value["description"], str) \ + or planet_value["description"] == '': + return abort(make_response(jsonify("Invalid request"), 400)) return planet_value # Routes functions diff --git a/tests/conftest.py b/tests/conftest.py index 74aa1fc4f..4a3212744 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -51,4 +51,4 @@ def three_planets(app): length_of_year = 365) db.session.add_all([planet_mercury, planet_venus, planet_earth]) - db.session.commit() \ No newline at end of file + db.session.commit() diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index 10ca7eb96..49773e610 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -6,7 +6,55 @@ def test_create_planet_valid_request(client): "name": "Mars" }) response_body = response.get_json() - + # Assert assert response.status_code == 201 - assert response_body == "Planet Mars successfully created" \ No newline at end of file + assert response_body == "Planet Mars successfully created" + +def test_create_planet_invalid_request_empty_name(client): + # Act + response = client.post("/planets", json = { + "name": "", + "description": "This unknown planet is the imaginary planet for purpose of testing.", + "length_of_year": 10}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +def test_create_planet_invalid_request_lenght_of_year_zero(client): + # Act + response = client.post("/planets", json = { + "name": "Test", + "description": "This unknown planet is the imaginary planet for purpose of testing.", + "length_of_year": 0}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +def test_create_planet_invalid_request_lenght_of_year_negative(client): + # Act + response = client.post("/planets", json = { + 'name': 'Test', + 'description': 'This unknown planet is the imaginary planet for purpose of testing.', + 'length_of_year': -100}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +def test_create_planet_invalid_request_description_empty(client): + # Act + response = client.post("/planets", json = { + 'name': 'Test', + 'description': '', + 'length_of_year': 10}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" \ No newline at end of file From 0eccad5bcfd2db0db32311b8e1ede43fe7aff186 Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 17:07:39 -0800 Subject: [PATCH 46/85] add test --- tests/test_routes.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test_routes.py b/tests/test_routes.py index e69de29bb..1124a9765 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -0,0 +1,8 @@ +def test_get_all_planets_with_no_records(client): + # Act + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == [] \ No newline at end of file From 0d348101f98201963dd0653d1cfd05b41e7c5a68 Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 17:08:42 -0800 Subject: [PATCH 47/85] delete some column --- app/routes/planet_routes.py | 71 ++++++++++++++++--------------------- tests/conftest.py | 26 ++++++++++++++ 2 files changed, 56 insertions(+), 41 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index eeb2fa16c..a5627b054 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -19,31 +19,20 @@ def validate_planet(planet_id): # Validating the user input to create or update the table planet # Returning the valid JSON if valid input -def validate_input(planet_value): - if "name" not in planet_value or not isinstance(planet_value["name"], str) \ - or "livable" not in planet_value or not isinstance(planet_value["livable"], bool) \ - or "number_of_moons" not in planet_value or not isinstance(planet_value["number_of_moons"], int) \ - or "length_of_year" not in planet_value or not isinstance(planet_value["length_of_year"], int) \ - or "namesake" not in planet_value or not isinstance(planet_value["namesake"], str) \ - or "atmosphere" not in planet_value or not isinstance(planet_value["atmosphere"], str) \ - or "diameter" not in planet_value or not isinstance(planet_value["diameter"], str) \ - or "description" not in planet_value or not isinstance(planet_value["description"], str): - return abort(make_response(f"Invalid request", 400)) - return planet_value - +def ? # Routes functions # Creating new record in the database Planet @planets_bp.route("", methods = ["POST"]) def create_planet(): - planet_value = validate_input(request.get_json()) + planet_value = request.get_json() new_planet = Planet( name = planet_value["name"], - livable = planet_value["livable"], - number_of_moons = planet_value["number_of_moons"], + #livable = planet_value["livable"], + #number_of_moons = planet_value["number_of_moons"], length_of_year = planet_value["length_of_year"], - namesake = planet_value["namesake"], - atmosphere = planet_value["atmosphere"], - diameter = planet_value["diameter"], + #namesake = planet_value["namesake"], + #atmosphere = planet_value["atmosphere"], + #diameter = planet_value["diameter"], description = planet_value["description"]) db.session.add(new_planet) @@ -61,9 +50,9 @@ def get_planets_query(): if planet_name_query: planet_query = planet_query.filter(Planet.name.ilike(f"%{planet_name_query}%")) - planet_livable_query = request.args.get("livable") - if planet_livable_query: - planet_query = planet_query.filter_by(livable = planet_livable_query) + # planet_livable_query = request.args.get("livable") + # if planet_livable_query: + # planet_query = planet_query.filter_by(livable = planet_livable_query) sort_by_name_query = request.args.get("sort_by_name") @@ -72,11 +61,11 @@ def get_planets_query(): elif sort_by_name_query == "asc": planet_query = planet_query.order_by(Planet.name).all() - sort_by_number_of_moons_query = request.args.get("sort_by_number_of_moons") - if sort_by_number_of_moons_query == "desc": - planet_query = planet_query.order_by(Planet.number_of_moons.desc()).all() - elif sort_by_number_of_moons_query == "asc": - planet_query = planet_query.order_by(Planet.number_of_moons).all() + # sort_by_number_of_moons_query = request.args.get("sort_by_number_of_moons") + # if sort_by_number_of_moons_query == "desc": + # planet_query = planet_query.order_by(Planet.number_of_moons.desc()).all() + # elif sort_by_number_of_moons_query == "asc": + # planet_query = planet_query.order_by(Planet.number_of_moons).all() sort_by_length_of_year_query = request.args.get("sort_by_length_of_year") if sort_by_length_of_year_query == "desc": @@ -90,12 +79,12 @@ def get_planets_query(): { "id": planet.id, "name": planet.name, - "livable": planet.livable, - "number_of_moons": planet.number_of_moons, + #"livable": planet.livable, + #"number_of_moons": planet.number_of_moons, "length_of_year": planet.length_of_year, - "namesake": planet.namesake, - "atmosphere": planet.atmosphere, - "diameter": planet.diameter, + #"namesake": planet.namesake, + #"atmosphere": planet.atmosphere, + #"diameter": planet.diameter, "description": planet.description }) return jsonify(planet_response), 200 @@ -108,12 +97,12 @@ def get_one_planet(planet_id): return { "id": planet.id, "name": planet.name, - "livable": planet.livable, - "number_of_moons": planet.number_of_moons, + #"livable": planet.livable, + #"number_of_moons": planet.number_of_moons, "length_of_year": planet.length_of_year, - "namesake": planet.namesake, - "atmosphere": planet.atmosphere, - "diameter": planet.diameter, + #"namesake": planet.namesake, + #"atmosphere": planet.atmosphere, + #"diameter": planet.diameter, "description": planet.description } @@ -124,12 +113,12 @@ def update_planet(planet_id): request_body = validate_input(request.get_json()) planet.name = request_body["name"], - planet.livable = request_body["livable"], - planet.number_of_moons = request_body["number_of_moons"], + #planet.livable = request_body["livable"], + #planet.number_of_moons = request_body["number_of_moons"], planet.length_of_year = request_body["length_of_year"], - planet.namesake = request_body["namesake"], - planet.atmosphere = request_body["atmosphere"], - planet.meter = request_body["diameter"], + #planet.namesake = request_body["namesake"], + #planet.atmosphere = request_body["atmosphere"], + #planet.meter = request_body["diameter"], planet.description = request_body["description"] db.session.commit() diff --git a/tests/conftest.py b/tests/conftest.py index e69de29bb..f81c15b95 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -0,0 +1,26 @@ +import pytest +from app import create_app +from app import db +from flask.signals import request_finished +from app.models.planet import Planet + +@pytest.fixture +def app(): + app = create_app({"TESTING": True}) + + @request_finished.connect_via(app) + def expire_session(sender, response, **extra): + db.session.remove() + + with app.app_context(): + db.create_all() + yield app + + with app.app_context(): + db.drop_all() + + +@pytest.fixture +def client(app): + return app.test_client() + From 6ceeabd54c87ce21b806614abae4ecbce99b6679 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Tue, 3 Jan 2023 17:14:58 -0800 Subject: [PATCH 48/85] added tests for update_planet_route --- app/routes/planet_routes.py | 7 ++-- tests/conftest.py | 1 + tests/test_planet_routes.py | 79 ++++++++++++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 5 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index afe83164b..644dc6926 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -11,10 +11,10 @@ def validate_planet(planet_id): try: planet_id = int(planet_id) except: - abort(make_response({"message":f"Planet {planet_id} invalid"}, 400)) + abort(make_response(jsonify(f"Planet {planet_id} invalid"), 400)) planet = Planet.query.get(planet_id) if not planet: - abort(make_response({"message":f"Planet {planet_id} not found"}, 404)) + abort(make_response(jsonify(f"Planet {planet_id} not found"), 404)) return planet # Validating the user input to create or update the table planet @@ -103,8 +103,7 @@ def update_planet(planet_id): planet.description = request_body["description"] db.session.commit() - - return make_response(f"Planet {planet.id} successfully update.") + return make_response(jsonify(f"Planet {planet_id} successfully updated"), 200) # Delete one planet @planets_bp.route("/",methods=["DELETE"] ) diff --git a/tests/conftest.py b/tests/conftest.py index 4a3212744..6c59e90f3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -52,3 +52,4 @@ def three_planets(app): db.session.add_all([planet_mercury, planet_venus, planet_earth]) db.session.commit() + diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index 49773e610..d4bbf61fe 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -1,3 +1,4 @@ +### POST def test_create_planet_valid_request(client): # Act response = client.post("/planets", json = { @@ -57,4 +58,80 @@ def test_create_planet_invalid_request_description_empty(client): # Assert assert response.status_code == 400 - assert response_body == "Invalid request" \ No newline at end of file + assert response_body == "Invalid request" + +#### PUT +def test_update_planet_valid_request(client, one_planet): + # Act + planet_id = one_planet.id + response = client.put(f"/planets/{one_planet.id}", json = { + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + "length_of_year": 88, + "name": "Mercury_updated" + }) + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == f"Planet {planet_id} successfully updated" + +def test_update_planet_not_exist_id(client, one_planet): + # Act + response = client.put("/planets/9", json = { + "description": "Mars is a dusty, cold, desert world with a very thin atmosphere.", + "length_of_year": 687, + "name": "Mars" + }) + response_body = response.get_json() + + # Assert + assert response.status_code == 404 + assert response_body == f"Planet 9 not found" + +def test_update_planet_invalid_request_empty_name(client, one_planet): + # Act + response = client.put(f"/planets/{one_planet.id}", json = { + "name": "", + "description": "This unknown planet is the imaginary planet for purpose of testing.", + "length_of_year": 10}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +def test_update_planet_invalid_request_lenght_of_year_zero(client, one_planet): + # Act + response = client.put(f"/planets/{one_planet.id}", json = { + "name": "Test", + "description": "This unknown planet is the imaginary planet for purpose of testing.", + "length_of_year": 0}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +def test_update_planet_invalid_request_lenght_of_year_negative(client, one_planet): + # Act + response = client.put(f"/planets/{one_planet.id}", json = { + 'name': 'Test', + 'description': 'This unknown planet is the imaginary planet for purpose of testing.', + 'length_of_year': -100}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +def test_update_planet_invalid_request_description_empty(client, one_planet): + # Act + response = client.put(f"/planets/{one_planet.id}", json = { + 'name': 'Test', + 'description': '', + 'length_of_year': 10}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" From 2d8d9cee6d9d65dfbb28130e393c8b230ebc68df Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 17:37:43 -0800 Subject: [PATCH 49/85] delete file --- tests/test_routes.py | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 tests/test_routes.py diff --git a/tests/test_routes.py b/tests/test_routes.py deleted file mode 100644 index 1124a9765..000000000 --- a/tests/test_routes.py +++ /dev/null @@ -1,8 +0,0 @@ -def test_get_all_planets_with_no_records(client): - # Act - response = client.get("/planets") - response_body = response.get_json() - - # Assert - assert response.status_code == 200 - assert response_body == [] \ No newline at end of file From d8c9a460ac57cbbca8c585fb6d310c6e75e1216a Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 17:37:59 -0800 Subject: [PATCH 50/85] merge --- app/models/planet.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/models/planet.py b/app/models/planet.py index 481247c43..f2019f828 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -4,11 +4,5 @@ class Planet(db.Model): id = db.Column(db.Integer, primary_key = True, autoincrement = True) name = db.Column(db.String, nullable = False) -<<<<<<< HEAD - length_of_year = db.Column(db.Integer, nullable = False) - description = db.Column(db.String, nullable = False) - -======= length_of_year = db.Column(db.Integer, nullable = False) description = db.Column(db.String, nullable = False) ->>>>>>> 1ba96d17c15051edb945c00d33efce0c7b3ba55a From df09d72b23f99bbfc79688be1d2cf7d359d080ec Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 17:38:58 -0800 Subject: [PATCH 51/85] test get planet 1 from fixture one_planet --- tests/test_planet_routes.py | 44 +++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index d4bbf61fe..d94b145b7 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -135,3 +135,47 @@ def test_update_planet_invalid_request_description_empty(client, one_planet): # Assert assert response.status_code == 400 assert response_body == "Invalid request" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# GET +def test_get_planet1_return_200(client,one_planet): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + } \ No newline at end of file From 9e26dd0fd10173c5d2e08f9afbdb9d57503dd71e Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 17:47:58 -0800 Subject: [PATCH 52/85] add test get planet1 no fixture return 404 --- tests/test_planet_routes.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index d94b145b7..13a4f8120 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -166,7 +166,7 @@ def test_update_planet_invalid_request_description_empty(client, one_planet): # GET -def test_get_planet1_return_200(client,one_planet): +def test_get_planet1_from_fixture_one_planet_return_200(client,one_planet): # Act response = client.get("/planets/1") response_body = response.get_json() @@ -178,4 +178,28 @@ def test_get_planet1_return_200(client,one_planet): "name": "Mercury", "length_of_year": 88, "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." - } \ No newline at end of file + } + +def test_get_planet1_from_fixture_three_planet_return_200(client,three_planets): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + } + +def test_get_planet1_no_fixture_return_404(client): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 404 + assert response_body == "Planet 1 not found" + \ No newline at end of file From e7c7a3619e123f2236f189686eb6415808a4cf15 Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 17:52:05 -0800 Subject: [PATCH 53/85] add test get planets in array with fixture one_planet 200 --- tests/test_planet_routes.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index 13a4f8120..55fa2c55e 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -202,4 +202,19 @@ def test_get_planet1_no_fixture_return_404(client): # Assert assert response.status_code == 404 assert response_body == "Planet 1 not found" - \ No newline at end of file + +def test_get_planets_in_array_return_200(client,one_planet): + # Act + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == [ + { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + } + ] \ No newline at end of file From 9c2b426d98060f32a96fcbb4249a7fc5dfc531f5 Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 17:53:11 -0800 Subject: [PATCH 54/85] add len() --- tests/test_planet_routes.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index 55fa2c55e..2179a7edf 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -210,6 +210,7 @@ def test_get_planets_in_array_return_200(client,one_planet): # Assert assert response.status_code == 200 + assert len(response_body) == 1 assert response_body == [ { "id":1, From 06b9340b04eeb70f9cbd54d5e6ccd67ceef549d2 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Tue, 3 Jan 2023 17:59:30 -0800 Subject: [PATCH 55/85] add test delete_planet_by_id_valid_id --- app/models/planet.py | 5 ----- app/routes/planet_routes.py | 9 +++++---- tests/test_planet_routes.py | 14 ++++++++++++-- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/app/models/planet.py b/app/models/planet.py index 481247c43..dfa805ced 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -4,11 +4,6 @@ class Planet(db.Model): id = db.Column(db.Integer, primary_key = True, autoincrement = True) name = db.Column(db.String, nullable = False) -<<<<<<< HEAD length_of_year = db.Column(db.Integer, nullable = False) description = db.Column(db.String, nullable = False) -======= - length_of_year = db.Column(db.Integer, nullable = False) - description = db.Column(db.String, nullable = False) ->>>>>>> 1ba96d17c15051edb945c00d33efce0c7b3ba55a diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 9b57c401f..1e0e17bdf 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -22,13 +22,13 @@ def validate_planet(planet_id): def validate_input(planet_value): if "name" not in planet_value \ or not isinstance(planet_value["name"], str) \ - or planet_value["name"] == '' \ + or planet_value["name"] == "" \ or "length_of_year" not in planet_value \ or not isinstance(planet_value["length_of_year"], int) \ or planet_value["length_of_year"] <=0 \ or "description" not in planet_value \ or not isinstance(planet_value["description"], str) \ - or planet_value["description"] == '': + or planet_value["description"] == "": return abort(make_response(jsonify("Invalid request"), 400)) return planet_value @@ -36,7 +36,8 @@ def validate_input(planet_value): # Creating new record in the database Planet @planets_bp.route("", methods = ["POST"]) def create_planet(): - planet_value = request.get_json() + planet_value = validate_input(request.get_json()) + new_planet = Planet( name = planet_value["name"], length_of_year = planet_value["length_of_year"], @@ -112,4 +113,4 @@ def delete_planet(planet_id): db.session.delete(planet) db.session.commit() - return make_response(f"Planet {planet.id} successfully delete.") \ No newline at end of file + return make_response(jsonify(f"Planet {planet.id} successfully deleted"), 200) \ No newline at end of file diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index d4bbf61fe..8f12d0524 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -1,4 +1,4 @@ -### POST +#### POST #### def test_create_planet_valid_request(client): # Act response = client.post("/planets", json = { @@ -60,7 +60,7 @@ def test_create_planet_invalid_request_description_empty(client): assert response.status_code == 400 assert response_body == "Invalid request" -#### PUT +#### PUT #### def test_update_planet_valid_request(client, one_planet): # Act planet_id = one_planet.id @@ -135,3 +135,13 @@ def test_update_planet_invalid_request_description_empty(client, one_planet): # Assert assert response.status_code == 400 assert response_body == "Invalid request" + +#### DELETE #### +def test_delete_planet_by_id_valid_request(client, one_planet): + # Act + planet_id = one_planet.id + response = client.delete(f"/planets/{planet_id}") + response_body = response.get_json() + # Assert + assert response.status_code == 200 + assert response_body == f"Planet {planet_id} successfully deleted" \ No newline at end of file From c5a68f701c2e7e309d82556aa43136e51bcbd02f Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 18:00:12 -0800 Subject: [PATCH 56/85] add test get planets in array with fixture three planets --- tests/test_planet_routes.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index 2179a7edf..89de007a0 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -218,4 +218,33 @@ def test_get_planets_in_array_return_200(client,one_planet): "length_of_year": 88, "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." } - ] \ No newline at end of file + ] + +def test_get_planets_in_array_with_fixture_three_planets_return_200(client,three_planets): + # Act + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert len(response_body) == 3 + assert response_body == [ + { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + }, + { + "id":2, + "name": "Venus", + "length_of_year": 225, + "description": "Venus spins slowly in the opposite direction from most planets." + }, + { + "id":3, + "name": "Earth", + "length_of_year": 365, + "description": "Earth — our home planet." + } +] \ No newline at end of file From e95fc926f6a919f93b6b9fcd5d5f3c6396fc6269 Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 18:31:02 -0800 Subject: [PATCH 57/85] all test pass --- app/routes/planet_routes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 1e0e17bdf..cc10ca537 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -52,7 +52,7 @@ def create_planet(): @planets_bp.route("", methods = ["GET"]) def get_planets_query(): planet_query = Planet.query - # Filtering by name (return all records whitch name contains planet_name_query) + # Filtering by name (return all records which name contains planet_name_query) planet_name_query = request.args.get("name") if planet_name_query: @@ -82,7 +82,7 @@ def get_planets_query(): return jsonify(planet_response), 200 # Read one planet -# Return one panet info in JSON format +# Return one planet info in JSON format @planets_bp.route("/",methods=["GET"] ) def get_one_planet(planet_id): planet = validate_planet(planet_id) From 78fe3fdf51223128cacaf0339867178a03f00b38 Mon Sep 17 00:00:00 2001 From: annadu Date: Tue, 3 Jan 2023 18:37:41 -0800 Subject: [PATCH 58/85] pass wave 6 --- tests/test_planet_routes.py | 88 ++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index 8f12d0524..573ee39b5 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -144,4 +144,90 @@ def test_delete_planet_by_id_valid_request(client, one_planet): response_body = response.get_json() # Assert assert response.status_code == 200 - assert response_body == f"Planet {planet_id} successfully deleted" \ No newline at end of file + assert response_body == f"Planet {planet_id} successfully deleted" + + + +####GET#### +def test_get_planet1_from_fixture_one_planet_return_200(client,one_planet): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + } + +def test_get_planet1_from_fixture_three_planet_return_200(client,three_planets): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + } + +def test_get_planet1_no_fixture_return_404(client): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 404 + assert response_body == "Planet 1 not found" + +def test_get_planets_in_array_return_200(client,one_planet): + # Act + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert len(response_body) == 1 + assert response_body == [ + { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + } + ] + +def test_get_planets_in_array_with_fixture_three_planets_return_200(client,three_planets): + # Act + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert len(response_body) == 3 + assert response_body == [ + { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + }, + { + "id":2, + "name": "Venus", + "length_of_year": 225, + "description": "Venus spins slowly in the opposite direction from most planets." + }, + { + "id":3, + "name": "Earth", + "length_of_year": 365, + "description": "Earth — our home planet." + } +] \ No newline at end of file From dabc7954f19337ab5fbd311dbd3cc1be0cc1d9ff Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Tue, 3 Jan 2023 18:43:55 -0800 Subject: [PATCH 59/85] Wave 06: complete --- tests/test_planet_routes.py | 87 ++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index 8f12d0524..1f034d58a 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -144,4 +144,89 @@ def test_delete_planet_by_id_valid_request(client, one_planet): response_body = response.get_json() # Assert assert response.status_code == 200 - assert response_body == f"Planet {planet_id} successfully deleted" \ No newline at end of file + assert response_body == f"Planet {planet_id} successfully deleted" + +#### GET #### +def test_get_planet1_return_200(client,one_planet): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + } + +def test_get_planet1_from_fixture_three_planet_return_200(client,three_planets): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + } + +def test_get_planet1_no_fixture_return_404(client): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 404 + assert response_body == "Planet 1 not found" + +def test_get_planets_in_array_return_200(client,one_planet): + # Act + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert len(response_body) == 1 + assert response_body == [ + { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + } + ] + +def test_get_planets_in_array_with_fixture_three_planets_return_200(client, three_planets): + # Act + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert len(response_body) == 3 + assert response_body == [ + { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + }, + { + "id":2, + "name": "Venus", + "length_of_year": 225, + "description": "Venus spins slowly in the opposite direction from most planets." + }, + { + "id":3, + "name": "Earth", + "length_of_year": 365, + "description": "Earth — our home planet." + } +] + From 3e633861e419e8cd00a7d0754d4f54d176116c4a Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Tue, 3 Jan 2023 18:58:16 -0800 Subject: [PATCH 60/85] added the edge case for delete_planet_by_id --- tests/test_planet_routes.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index 3ff5601ee..7e9d7f441 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -146,6 +146,17 @@ def test_delete_planet_by_id_valid_request(client, one_planet): assert response.status_code == 200 assert response_body == f"Planet {planet_id} successfully deleted" +def test_delete_planet_by_id_invalid_id(client, one_planet): + # Act + # Act + planet_id = "hello" + response = client.delete(f"/planets/{planet_id}") + response_body = response.get_json() + # Assert + assert response.status_code == 400 + assert response_body == f"Planet {planet_id} invalid" + + ####GET#### def test_get_planet1_from_fixture_one_planet_return_200(client,one_planet): # Act From 900d2cac6d403472fd53e5b0304ddb7380463012 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Tue, 3 Jan 2023 18:59:29 -0800 Subject: [PATCH 61/85] Added test_delete_planet with invalid id. --- tests/test_planet_routes.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index 7e9d7f441..124e03927 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -148,7 +148,6 @@ def test_delete_planet_by_id_valid_request(client, one_planet): def test_delete_planet_by_id_invalid_id(client, one_planet): # Act - # Act planet_id = "hello" response = client.delete(f"/planets/{planet_id}") response_body = response.get_json() @@ -156,7 +155,6 @@ def test_delete_planet_by_id_invalid_id(client, one_planet): assert response.status_code == 400 assert response_body == f"Planet {planet_id} invalid" - ####GET#### def test_get_planet1_from_fixture_one_planet_return_200(client,one_planet): # Act From a7bf91dd5488e498875068861a870399a4aad8fb Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Tue, 3 Jan 2023 19:13:56 -0800 Subject: [PATCH 62/85] added two edge cases for delete_by_id and update_by_id --- tests/test_planet_routes.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index 124e03927..fb4a75fae 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -88,6 +88,19 @@ def test_update_planet_not_exist_id(client, one_planet): assert response.status_code == 404 assert response_body == f"Planet 9 not found" +def test_update_planet_invalid_type_id(client, one_planet): + # Act + planet_id = "hello" + response = client.put(f"/planets/{planet_id}", json = { + "description": "Mars is a dusty, cold, desert world with a very thin atmosphere.", + "length_of_year": 687, + "name": "Mars" + }) + response_body = response.get_json() + # Assert + assert response.status_code == 400 + assert response_body == f"Planet {planet_id} invalid" + def test_update_planet_invalid_request_empty_name(client, one_planet): # Act response = client.put(f"/planets/{one_planet.id}", json = { @@ -155,6 +168,14 @@ def test_delete_planet_by_id_invalid_id(client, one_planet): assert response.status_code == 400 assert response_body == f"Planet {planet_id} invalid" +def test_delete_planet_by_not_existed_id(client, one_planet): + planet_id = 9 + response = client.delete(f"/planets/{planet_id}") + response_body = response.get_json() + # Assert + assert response.status_code == 404 + assert response_body == f"Planet {planet_id} not found" + ####GET#### def test_get_planet1_from_fixture_one_planet_return_200(client,one_planet): # Act From a589a31a5fb9c14748d9bfabeb4597bb32131db3 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Wed, 4 Jan 2023 10:35:13 -0800 Subject: [PATCH 63/85] Refactoring validate_id --- app/models/planet.py | 17 +++++- app/routes/planet_routes.py | 39 +++++-------- tests/test.models.py | 111 ++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 27 deletions(-) create mode 100644 tests/test.models.py diff --git a/app/models/planet.py b/app/models/planet.py index dfa805ced..427b2e863 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -6,4 +6,19 @@ class Planet(db.Model): name = db.Column(db.String, nullable = False) length_of_year = db.Column(db.Integer, nullable = False) description = db.Column(db.String, nullable = False) - + + def to_dict(self): + planet_as_dict = {} + planet_as_dict["id"] = self.id + planet_as_dict["name"] = self.name + planet_as_dict["length_of_year"] = self.length_of_year + planet_as_dict["description"] = self.description + return planet_as_dict + + + @classmethod + def from_dict(cls,planet_data): + new_planet = Planet(name=planet_data["name"], + length_of_year=planet_data["length_of_year"], + description=planet_data["description"]) + return new_planet \ No newline at end of file diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index cc10ca537..4a44f366b 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -7,14 +7,14 @@ # Helper functions # Validating the id of the planet: id needs to be int and exists the planet with the id. # Returning the valid Planet instance if valid id -def validate_planet(planet_id): +def validate_model(cls, model_id): try: - planet_id = int(planet_id) + model_id = int(model_id) except: - abort(make_response(jsonify(f"Planet {planet_id} invalid"), 400)) - planet = Planet.query.get(planet_id) + abort(make_response(jsonify(f"{cls.__name__} {model_id} invalid"), 400)) + planet = Planet.query.get(model_id) if not planet: - abort(make_response(jsonify(f"Planet {planet_id} not found"), 404)) + abort(make_response(jsonify(f"{cls.__name__} {model_id} not found"), 404)) return planet # Validating the user input to create or update the table planet @@ -38,10 +38,7 @@ def validate_input(planet_value): def create_planet(): planet_value = validate_input(request.get_json()) - new_planet = Planet( - name = planet_value["name"], - length_of_year = planet_value["length_of_year"], - description = planet_value["description"]) + new_planet = Planet.from_dict(planet_value) db.session.add(new_planet) db.session.commit() @@ -69,34 +66,24 @@ def get_planets_query(): planet_query = planet_query.order_by(Planet.length_of_year.desc()).all() elif sort_by_length_of_year_query == "asc": planet_query = planet_query.order_by(Planet.length_of_year).all() - + planet_response = [] for planet in planet_query: - planet_response.append( - { - "id": planet.id, - "name": planet.name, - "length_of_year": planet.length_of_year, - "description": planet.description - }) + planet_response.append(planet.to_dict()) + return jsonify(planet_response), 200 # Read one planet # Return one planet info in JSON format @planets_bp.route("/",methods=["GET"] ) def get_one_planet(planet_id): - planet = validate_planet(planet_id) - return { - "id": planet.id, - "name": planet.name, - "length_of_year": planet.length_of_year, - "description": planet.description - } + planet = validate_model(Planet, planet_id) + return planet.to_dict() # Update one planet @planets_bp.route("/",methods=["PUT"] ) def update_planet(planet_id): - planet = validate_planet(planet_id) + planet = validate_model(Planet, planet_id) request_body = validate_input(request.get_json()) planet.name = request_body["name"], @@ -109,7 +96,7 @@ def update_planet(planet_id): # Delete one planet @planets_bp.route("/",methods=["DELETE"] ) def delete_planet(planet_id): - planet = validate_planet(planet_id) + planet = validate_model(Planet, planet_id) db.session.delete(planet) db.session.commit() diff --git a/tests/test.models.py b/tests/test.models.py new file mode 100644 index 000000000..c269cf691 --- /dev/null +++ b/tests/test.models.py @@ -0,0 +1,111 @@ +from app.models.planet import Planet +import pytest + +def test_to_dict_no_missing_data(): + # Arrange + test_data = Planet(id = 1, + name="Test", + description="Imaginary for testing", + length_of_year = 100) + + # Act + result = test_data.to_dict() + + # Assert + assert len(result) == 4 + assert result["id"] == 1 + assert result["length_of_year"] == 100 + assert result["description"] == "Imaginary for testing" + +def test_to_dict_missing_id(): + # Arrange + test_data = Planet(title="Test", + description="Imaginary for testing", + length_of_year = 100 + ) + + # Act + result = test_data.to_dict() + + # Assert + assert len(result) == 4 + assert result["id"] == 1 + assert result["length_of_year"] == 100 + assert result["description"] == "Imaginary for testing" + +# def test_to_dict_missing_name(): +# # Arrange +# test_data = Planet(id=1, +# description="Imaginary for testing", +# ) + +# # Act +# result = test_data.to_dict() + +# # Assert +# assert response.status_code == 400 +# assert response_body == "Invalid request" + +# def test_to_dict_missing_description(): +# # Arrange +# test_data = Book(id = 1, +# title="Ocean Book") + +# # Act +# result = test_data.to_dict() + +# # Assert +# assert len(result) == 4 +# assert result["id"] == 1 +# assert result["length_of_year"] == 100 +# assert result["description"] == "Imaginary for testing" + +# def test_from_dict_returns_book(): +# # Arrange +# book_data = { +# "title": "New Book", +# "description": "The Best!" +# } + +# # Act +# new_book = Book.from_dict(book_data) + +# # Assert +# assert new_book.title == "New Book" +# assert new_book.description == "The Best!" + +# def test_from_dict_with_no_title(): +# # Arrange +# book_data = { +# "description": "The Best!" +# } + +# # Act & Assert +# with pytest.raises(KeyError, match = 'title'): +# new_book = Book.from_dict(book_data) + +# def test_from_dict_with_no_description(): +# # Arrange +# book_data = { +# "title": "New Book" +# } + +# # Act & Assert +# with pytest.raises(KeyError, match = 'description'): +# new_book = Book.from_dict(book_data) + +# def test_from_dict_with_extra_keys(): +# # Arrange +# book_data = { +# "extra": "some stuff", +# "title": "New Book", +# "description": "The Best!", +# "another": "last value" +# } + +# # Act +# new_book = Book.from_dict(book_data) + +# # Assert +# assert new_book.title == "New Book" +# assert new_book.description == "The Best!" \ No newline at end of file From 7a600572dad1284f8578960b3ceddc848fcebe5b Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Wed, 4 Jan 2023 11:51:05 -0800 Subject: [PATCH 64/85] test_to_dict --- app/models/planet.py | 6 +-- tests/{test.models.py => test_models.py} | 62 ++++++++++++------------ 2 files changed, 33 insertions(+), 35 deletions(-) rename tests/{test.models.py => test_models.py} (67%) diff --git a/app/models/planet.py b/app/models/planet.py index 427b2e863..80ff22f05 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -6,7 +6,7 @@ class Planet(db.Model): name = db.Column(db.String, nullable = False) length_of_year = db.Column(db.Integer, nullable = False) description = db.Column(db.String, nullable = False) - + def to_dict(self): planet_as_dict = {} planet_as_dict["id"] = self.id @@ -19,6 +19,6 @@ def to_dict(self): @classmethod def from_dict(cls,planet_data): new_planet = Planet(name=planet_data["name"], - length_of_year=planet_data["length_of_year"], - description=planet_data["description"]) + length_of_year=planet_data["length_of_year"], + description=planet_data["description"]) return new_planet \ No newline at end of file diff --git a/tests/test.models.py b/tests/test_models.py similarity index 67% rename from tests/test.models.py rename to tests/test_models.py index c269cf691..792d04c81 100644 --- a/tests/test.models.py +++ b/tests/test_models.py @@ -1,66 +1,64 @@ +from app import db from app.models.planet import Planet import pytest def test_to_dict_no_missing_data(): # Arrange - test_data = Planet(id = 1, + test_data = Planet( name="Test", description="Imaginary for testing", length_of_year = 100) # Act result = test_data.to_dict() - # Assert assert len(result) == 4 - assert result["id"] == 1 + assert result["name"] == "Test" assert result["length_of_year"] == 100 assert result["description"] == "Imaginary for testing" def test_to_dict_missing_id(): # Arrange - test_data = Planet(title="Test", + test_data = Planet(name="Test", description="Imaginary for testing", length_of_year = 100 ) - # Act result = test_data.to_dict() - # Assert assert len(result) == 4 - assert result["id"] == 1 + assert result["name"] == "Test" assert result["length_of_year"] == 100 assert result["description"] == "Imaginary for testing" -# def test_to_dict_missing_name(): -# # Arrange -# test_data = Planet(id=1, -# description="Imaginary for testing", -# ) - -# # Act -# result = test_data.to_dict() - -# # Assert -# assert response.status_code == 400 -# assert response_body == "Invalid request" - -# def test_to_dict_missing_description(): -# # Arrange -# test_data = Book(id = 1, -# title="Ocean Book") +def test_to_dict_missing_name(): +# Arrange + test_data = Planet( + description="Imaginary for testing", + length_of_year = 100 + ) -# # Act -# result = test_data.to_dict() +# Act + result = test_data.to_dict() +# Assert + assert len(result) == 4 + assert result["name"] == None + assert result["length_of_year"] == 100 + assert result["description"] == "Imaginary for testing" -# # Assert -# assert len(result) == 4 -# assert result["id"] == 1 -# assert result["length_of_year"] == 100 -# assert result["description"] == "Imaginary for testing" +def test_to_dict_missing_description(): +# Arrange + test_data = Planet(name="Test", + length_of_year = 100) +# Act + result = test_data.to_dict() +# Assert + assert len(result) == 4 + assert result["name"] == "Test" + assert result["length_of_year"] == 100 + assert result["description"] == None -# def test_from_dict_returns_book(): +#def test_from_dict_returns_book(): # # Arrange # book_data = { # "title": "New Book", From 9c5ec286f36c35e92404429c15c1fd53f077b4a9 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Wed, 4 Jan 2023 12:03:41 -0800 Subject: [PATCH 65/85] Added test_from_dict cases --- tests/test_models.py | 91 ++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/tests/test_models.py b/tests/test_models.py index 792d04c81..a02817d88 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -58,52 +58,51 @@ def test_to_dict_missing_description(): assert result["length_of_year"] == 100 assert result["description"] == None -#def test_from_dict_returns_book(): -# # Arrange -# book_data = { -# "title": "New Book", -# "description": "The Best!" -# } - -# # Act -# new_book = Book.from_dict(book_data) - -# # Assert -# assert new_book.title == "New Book" -# assert new_book.description == "The Best!" - -# def test_from_dict_with_no_title(): -# # Arrange -# book_data = { -# "description": "The Best!" -# } - -# # Act & Assert -# with pytest.raises(KeyError, match = 'title'): -# new_book = Book.from_dict(book_data) - -# def test_from_dict_with_no_description(): -# # Arrange -# book_data = { -# "title": "New Book" -# } +def test_from_dict_returns_planet(): +# Arrange + planet_data = { + "name": "Test", + "length_of_year": 100, + "description": "Imaginary for testing" + } +# Act + new_planet = Planet.from_dict(planet_data) +# Assert + assert new_planet.name == "Test" + assert new_planet.length_of_year == 100 + assert new_planet.description == "Imaginary for testing" -# # Act & Assert -# with pytest.raises(KeyError, match = 'description'): -# new_book = Book.from_dict(book_data) +def test_from_dict_with_no_name(): +# Arrange + planet_data = { + "length_of_year": 100, + "description": "Imaginary for testing" + } +# Act & Assert + with pytest.raises(KeyError, match = 'name'): + new_planet = Planet.from_dict(planet_data) -# def test_from_dict_with_extra_keys(): -# # Arrange -# book_data = { -# "extra": "some stuff", -# "title": "New Book", -# "description": "The Best!", -# "another": "last value" -# } - -# # Act -# new_book = Book.from_dict(book_data) +def test_from_dict_with_no_description(): +# Arrange + planet_data = { + "name": "Test", + "length_of_year": 100, + } +# Act & Assert + with pytest.raises(KeyError, match = 'description'): + new_planet = Planet.from_dict(planet_data) -# # Assert -# assert new_book.title == "New Book" -# assert new_book.description == "The Best!" \ No newline at end of file +def test_from_dict_with_extra_keys(): +# Arrange + planet_data = { + "name": "Test", + "length_of_year": 100, + "description": "Imaginary for testing", + "number_of_moons": 9 + } +# Act + new_planet = Planet.from_dict(planet_data) +# Assert + assert new_planet.name == "Test" + assert new_planet.length_of_year == 100 + assert new_planet.description == "Imaginary for testing" \ No newline at end of file From 9bf3d44ce506b956e8bf36ba4f11243ddaf18245 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Wed, 4 Jan 2023 13:35:33 -0800 Subject: [PATCH 66/85] test validate_model --- tests/test_planet_routes.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index fb4a75fae..b4fada3de 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -1,3 +1,8 @@ +from werkzeug.exceptions import HTTPException +from app.routes.planet_routes import validate_model +from app.models.planet import Planet +import pytest + #### POST #### def test_create_planet_valid_request(client): # Act @@ -259,3 +264,27 @@ def test_get_planets_in_array_with_fixture_three_planets_return_200(client,three "description": "Earth — our home planet." } ] + +####validate_model#### +def test_validate_model(three_planets): + # Act + result_planet = validate_model(Planet, 1) + # Assert + assert result_planet.id == 1 + assert result_planet.name == "Mercury" + assert result_planet.length_of_year == 88 + assert result_planet.description == "Mercury is the smallest planet in the Solar System and the closest to the Sun." + +def test_validate_model_missing_record(three_planets): + # Act & Assert + # Calling `validate_book` without being invoked by a route will + # cause an `HTTPException` when an `abort` statement is reached + with pytest.raises(HTTPException): + result_planet = validate_model(Planet, 9) + +def test_validate_model_invalid_id(three_planets): + # Act & Assert + # Calling `validate_book` without being invoked by a route will + # cause an `HTTPException` when an `abort` statement is reached + with pytest.raises(HTTPException): + result_planet = validate_model(Planet, "hello") From 9b29f4136bfd4f0b92c48dc1994f647fda987806 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Wed, 4 Jan 2023 13:45:17 -0800 Subject: [PATCH 67/85] complete wave7 --- app/routes/planet_routes.py | 7 +++---- tests/test_planet_routes.py | 4 +++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 4a44f366b..40a4b7247 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -12,10 +12,10 @@ def validate_model(cls, model_id): model_id = int(model_id) except: abort(make_response(jsonify(f"{cls.__name__} {model_id} invalid"), 400)) - planet = Planet.query.get(model_id) - if not planet: + class_obj = cls.query.get(model_id) + if not class_obj: abort(make_response(jsonify(f"{cls.__name__} {model_id} not found"), 404)) - return planet + return class_obj # Validating the user input to create or update the table planet # Returning the valid JSON if valid input @@ -37,7 +37,6 @@ def validate_input(planet_value): @planets_bp.route("", methods = ["POST"]) def create_planet(): planet_value = validate_input(request.get_json()) - new_planet = Planet.from_dict(planet_value) db.session.add(new_planet) diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index b4fada3de..3191860ef 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -265,7 +265,7 @@ def test_get_planets_in_array_with_fixture_three_planets_return_200(client,three } ] -####validate_model#### +#### tests for validate_model #### def test_validate_model(three_planets): # Act result_planet = validate_model(Planet, 1) @@ -288,3 +288,5 @@ def test_validate_model_invalid_id(three_planets): # cause an `HTTPException` when an `abort` statement is reached with pytest.raises(HTTPException): result_planet = validate_model(Planet, "hello") + +#### tests for validate_input #### From 7b82c792340141296d7c7bdc4565533aeb8f9482 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 5 Jan 2023 10:43:19 -0800 Subject: [PATCH 68/85] added moon model --- app/__init__.py | 3 +++ app/models/moon.py | 25 +++++++++++++++++++++++++ app/models/planet.py | 1 + app/routes/moon_routes.py | 6 ++++++ app/routes/planet_routes.py | 6 +++--- 5 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 app/models/moon.py create mode 100644 app/routes/moon_routes.py diff --git a/app/__init__.py b/app/__init__.py index 43e6f352d..0abe0d353 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -24,8 +24,11 @@ def create_app(test_config = None): migrate.init_app(app, db) from app.models.planet import Planet + from app.models.moon import Moon from .routes.planet_routes import planets_bp app.register_blueprint(planets_bp) + from .routes.moon_routes import moons_bp + app.register_blueprint(moons_bp) return app \ No newline at end of file diff --git a/app/models/moon.py b/app/models/moon.py new file mode 100644 index 000000000..e0dd820c7 --- /dev/null +++ b/app/models/moon.py @@ -0,0 +1,25 @@ +from app import db + +class Moon(db.Model): + id = db.Column(db.Integer, primary_key = True, autoincrement = True) + name = db.Column(db.String, nullable = False) + size = db.Column(db.String, nullable = False) + description = db.Column(db.String, nullable = False) + planet_id = db.Column(db.Integer, db.ForeignKey("planet.id")) + planet = db.relationship("Planet", back_populates="moons") + + def to_dict(self): + moon_as_dict = {} + moon_as_dict["id"] = self.id + moon_as_dict["name"] = self.name + moon_as_dict["size"] = self.size + moon_as_dict["description"] = self.description + return moon_as_dict + + + @classmethod + def from_dict(cls,moon_data): + new_moon = Moon(name=moon_data["name"], + size=moon_data["size"], + description=moon_data["description"]) + return new_moon \ No newline at end of file diff --git a/app/models/planet.py b/app/models/planet.py index 80ff22f05..a228905b5 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -6,6 +6,7 @@ class Planet(db.Model): name = db.Column(db.String, nullable = False) length_of_year = db.Column(db.Integer, nullable = False) description = db.Column(db.String, nullable = False) + moons = db.relationship("Moon", back_populates="planets") def to_dict(self): planet_as_dict = {} diff --git a/app/routes/moon_routes.py b/app/routes/moon_routes.py new file mode 100644 index 000000000..2a6cf949e --- /dev/null +++ b/app/routes/moon_routes.py @@ -0,0 +1,6 @@ +from app import db +from app.models.moon import Moon +from flask import Blueprint, jsonify, abort, make_response, request +from .planet_routes import validate_model + +moons_bp = Blueprint("moons_bp", __name__, url_prefix = "/moons") \ No newline at end of file diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 40a4b7247..c4275a61f 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -85,15 +85,15 @@ def update_planet(planet_id): planet = validate_model(Planet, planet_id) request_body = validate_input(request.get_json()) - planet.name = request_body["name"], - planet.length_of_year = request_body["length_of_year"], + planet.name = request_body["name"] + planet.length_of_year = request_body["length_of_year"] planet.description = request_body["description"] db.session.commit() return make_response(jsonify(f"Planet {planet_id} successfully updated"), 200) # Delete one planet -@planets_bp.route("/",methods=["DELETE"] ) +@planets_bp.route("/",methods=["DELETE"]) def delete_planet(planet_id): planet = validate_model(Planet, planet_id) db.session.delete(planet) From 80a8862be7f6c590719371bbcdb11548b4e2c21c Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 5 Jan 2023 11:45:33 -0800 Subject: [PATCH 69/85] add routes for moon model --- app/routes/moon_routes.py | 43 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/app/routes/moon_routes.py b/app/routes/moon_routes.py index 2a6cf949e..37614040e 100644 --- a/app/routes/moon_routes.py +++ b/app/routes/moon_routes.py @@ -3,4 +3,45 @@ from flask import Blueprint, jsonify, abort, make_response, request from .planet_routes import validate_model -moons_bp = Blueprint("moons_bp", __name__, url_prefix = "/moons") \ No newline at end of file +moons_bp = Blueprint("moons_bp", __name__, url_prefix = "/moons") + +#`/moons//moons` with the POST +@moons_bp.route("//moons", methods=["POST"]) +def create_moon(planet_id): + + planet = validate_model(Planet, planet_id) + + request_body = request.get_json() + new_moon = Moon.from_dict(request_body) + new_moon.planet = planet + + db.session.add(new_moon) + db.session.commit() + + message = f"Moon {new_moon.name} created with Planet {planet.name}" + return make_response(jsonify(message), 201) + +# Get all moons info +# Return JSON list +@moons_bp.route("", methods = ["GET"]) +def get_all_moons_query(): + moon_query = Moon.query + # Filtering by name (return all records which name contains planet_name_query) + moon_name_query = request.args.get("name") + + if moon_name_query: + moon_query = moon_query.filter(Moon.name.ilike(f"%{moon_name_query}%")) + + sort_by_name_query = request.args.get("sort_by_name") + if sort_by_name_query == "desc": + moon_query = moon_query.order_by(Moon.name.desc()).all() + elif sort_by_name_query == "asc": + moon_query = moon_query.order_by(Moon.name).all() + + moon_response = [] + for moon in moon_query: + moon_response.append(moon.to_dict()) + + return jsonify(moon_response), 200 + +#/planets//moons` with the GET method From 220c06bac11a836e3d336371d018972c428d52a8 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 5 Jan 2023 11:45:52 -0800 Subject: [PATCH 70/85] add routes for moon --- app/routes/moon_routes.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/routes/moon_routes.py b/app/routes/moon_routes.py index 37614040e..a17e86c64 100644 --- a/app/routes/moon_routes.py +++ b/app/routes/moon_routes.py @@ -1,5 +1,6 @@ from app import db from app.models.moon import Moon +from app.models.planet import Planet from flask import Blueprint, jsonify, abort, make_response, request from .planet_routes import validate_model @@ -45,3 +46,11 @@ def get_all_moons_query(): return jsonify(moon_response), 200 #/planets//moons` with the GET method +@moons_bp.route("//moons", methods=["GET"]) +def read_moons(planet_id): + planet = validate_model(Planet, planet_id) + + moons_response = [] + for moon in planet.moons: + moons_response.append(moon.to_dict()) + return jsonify(moons_response) \ No newline at end of file From 799b0164d242ecd7d09f50515d9c92b846d4d761 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 5 Jan 2023 11:51:50 -0800 Subject: [PATCH 71/85] added test_moon_routes.py --- app/models/planet.py | 2 -- tests/test_moon_routes.py | 0 2 files changed, 2 deletions(-) create mode 100644 tests/test_moon_routes.py diff --git a/app/models/planet.py b/app/models/planet.py index a228905b5..2036f9fd6 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -1,6 +1,5 @@ from app import db - class Planet(db.Model): id = db.Column(db.Integer, primary_key = True, autoincrement = True) name = db.Column(db.String, nullable = False) @@ -16,7 +15,6 @@ def to_dict(self): planet_as_dict["description"] = self.description return planet_as_dict - @classmethod def from_dict(cls,planet_data): new_planet = Planet(name=planet_data["name"], diff --git a/tests/test_moon_routes.py b/tests/test_moon_routes.py new file mode 100644 index 000000000..e69de29bb From 826486a5d8e38477540363232fb832bd21112dcc Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 5 Jan 2023 11:56:19 -0800 Subject: [PATCH 72/85] added moon_database_file --- moons_data.csv | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 moons_data.csv diff --git a/moons_data.csv b/moons_data.csv new file mode 100644 index 000000000..e69de29bb From 30c34a7c997b63716328feae7dced96f37070e8c Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 5 Jan 2023 16:13:18 -0800 Subject: [PATCH 73/85] Added moon model --- app/models/moon.py | 4 +- app/models/planet.py | 7 +- migrations/README | 2 +- migrations/alembic.ini | 7 +- migrations/env.py | 33 ++++--- .../60ee1bf3a6d7_delete_some_column.py | 36 -------- ...el.py => 8173d172e151_added_moon_model.py} | 18 +++- moons_data.csv | 62 +++++++++++++ tests/test_models.py | 86 +++++++++++++++---- tests/test_planet_routes.py | 18 ++-- 10 files changed, 194 insertions(+), 79 deletions(-) delete mode 100644 migrations/versions/60ee1bf3a6d7_delete_some_column.py rename migrations/versions/{00194cde28bc_adds_planet_model.py => 8173d172e151_added_moon_model.py} (57%) diff --git a/app/models/moon.py b/app/models/moon.py index e0dd820c7..36f372699 100644 --- a/app/models/moon.py +++ b/app/models/moon.py @@ -3,7 +3,7 @@ class Moon(db.Model): id = db.Column(db.Integer, primary_key = True, autoincrement = True) name = db.Column(db.String, nullable = False) - size = db.Column(db.String, nullable = False) + size = db.Column(db.Float, nullable = False) description = db.Column(db.String, nullable = False) planet_id = db.Column(db.Integer, db.ForeignKey("planet.id")) planet = db.relationship("Planet", back_populates="moons") @@ -20,6 +20,6 @@ def to_dict(self): @classmethod def from_dict(cls,moon_data): new_moon = Moon(name=moon_data["name"], - size=moon_data["size"], + size=float(moon_data["size"]), description=moon_data["description"]) return new_moon \ No newline at end of file diff --git a/app/models/planet.py b/app/models/planet.py index 2036f9fd6..bb7b7c0a6 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -5,7 +5,7 @@ class Planet(db.Model): name = db.Column(db.String, nullable = False) length_of_year = db.Column(db.Integer, nullable = False) description = db.Column(db.String, nullable = False) - moons = db.relationship("Moon", back_populates="planets") + moons = db.relationship("Moon", back_populates="planet") def to_dict(self): planet_as_dict = {} @@ -13,6 +13,11 @@ def to_dict(self): planet_as_dict["name"] = self.name planet_as_dict["length_of_year"] = self.length_of_year planet_as_dict["description"] = self.description + + moon_names = [] + for moon in self.moons: + moon_names.append(moon.name) + planet_as_dict["moons"] = moon_names return planet_as_dict @classmethod diff --git a/migrations/README b/migrations/README index 98e4f9c44..0e0484415 100644 --- a/migrations/README +++ b/migrations/README @@ -1 +1 @@ -Generic single-database configuration. \ No newline at end of file +Single-database configuration for Flask. diff --git a/migrations/alembic.ini b/migrations/alembic.ini index f8ed4801f..ec9d45c26 100644 --- a/migrations/alembic.ini +++ b/migrations/alembic.ini @@ -11,7 +11,7 @@ # Logging configuration [loggers] -keys = root,sqlalchemy,alembic +keys = root,sqlalchemy,alembic,flask_migrate [handlers] keys = console @@ -34,6 +34,11 @@ level = INFO handlers = qualname = alembic +[logger_flask_migrate] +level = INFO +handlers = +qualname = flask_migrate + [handler_console] class = StreamHandler args = (sys.stderr,) diff --git a/migrations/env.py b/migrations/env.py index 8b3fb3353..fa412e8c3 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -3,8 +3,6 @@ import logging from logging.config import fileConfig -from sqlalchemy import engine_from_config -from sqlalchemy import pool from flask import current_app from alembic import context @@ -18,14 +16,23 @@ fileConfig(config.config_file_name) logger = logging.getLogger('alembic.env') + +def get_engine(): + try: + # this works with Flask-SQLAlchemy<3 and Alchemical + return current_app.extensions['migrate'].db.get_engine() + except TypeError: + # this works with Flask-SQLAlchemy>=3 + return current_app.extensions['migrate'].db.engine + + # add your model's MetaData object here # for 'autogenerate' support # from myapp import mymodel # target_metadata = mymodel.Base.metadata config.set_main_option( - 'sqlalchemy.url', - str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%')) -target_metadata = current_app.extensions['migrate'].db.metadata + 'sqlalchemy.url', str(get_engine().url).replace('%', '%%')) +target_db = current_app.extensions['migrate'].db # other values from the config, defined by the needs of env.py, # can be acquired: @@ -33,6 +40,12 @@ # ... etc. +def get_metadata(): + if hasattr(target_db, 'metadatas'): + return target_db.metadatas[None] + return target_db.metadata + + def run_migrations_offline(): """Run migrations in 'offline' mode. @@ -47,7 +60,7 @@ def run_migrations_offline(): """ url = config.get_main_option("sqlalchemy.url") context.configure( - url=url, target_metadata=target_metadata, literal_binds=True + url=url, target_metadata=get_metadata(), literal_binds=True ) with context.begin_transaction(): @@ -72,16 +85,12 @@ def process_revision_directives(context, revision, directives): directives[:] = [] logger.info('No changes in schema detected.') - connectable = engine_from_config( - config.get_section(config.config_ini_section), - prefix='sqlalchemy.', - poolclass=pool.NullPool, - ) + connectable = get_engine() with connectable.connect() as connection: context.configure( connection=connection, - target_metadata=target_metadata, + target_metadata=get_metadata(), process_revision_directives=process_revision_directives, **current_app.extensions['migrate'].configure_args ) diff --git a/migrations/versions/60ee1bf3a6d7_delete_some_column.py b/migrations/versions/60ee1bf3a6d7_delete_some_column.py deleted file mode 100644 index f9f22a6c4..000000000 --- a/migrations/versions/60ee1bf3a6d7_delete_some_column.py +++ /dev/null @@ -1,36 +0,0 @@ -"""delete some column - -Revision ID: 60ee1bf3a6d7 -Revises: 927e0daedb50 -Create Date: 2023-01-03 12:32:11.382959 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = '60ee1bf3a6d7' -down_revision = '927e0daedb50' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('planet', 'namesake') - op.drop_column('planet', 'diameter') - op.drop_column('planet', 'livable') - op.drop_column('planet', 'number_of_moons') - op.drop_column('planet', 'atmosphere') - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('planet', sa.Column('atmosphere', sa.VARCHAR(), autoincrement=False, nullable=False)) - op.add_column('planet', sa.Column('number_of_moons', sa.INTEGER(), autoincrement=False, nullable=True)) - op.add_column('planet', sa.Column('livable', sa.BOOLEAN(), autoincrement=False, nullable=True)) - op.add_column('planet', sa.Column('diameter', sa.VARCHAR(), autoincrement=False, nullable=False)) - op.add_column('planet', sa.Column('namesake', sa.VARCHAR(), autoincrement=False, nullable=False)) - # ### end Alembic commands ### diff --git a/migrations/versions/00194cde28bc_adds_planet_model.py b/migrations/versions/8173d172e151_added_moon_model.py similarity index 57% rename from migrations/versions/00194cde28bc_adds_planet_model.py rename to migrations/versions/8173d172e151_added_moon_model.py index 0fd109ab6..e1062d68f 100644 --- a/migrations/versions/00194cde28bc_adds_planet_model.py +++ b/migrations/versions/8173d172e151_added_moon_model.py @@ -1,8 +1,8 @@ -"""adds Planet model +"""Added Moon model -Revision ID: 00194cde28bc +Revision ID: 8173d172e151 Revises: -Create Date: 2023-01-03 12:33:11.301835 +Create Date: 2023-01-05 15:31:57.115338 """ from alembic import op @@ -10,7 +10,7 @@ # revision identifiers, used by Alembic. -revision = '00194cde28bc' +revision = '8173d172e151' down_revision = None branch_labels = None depends_on = None @@ -25,10 +25,20 @@ def upgrade(): sa.Column('description', sa.String(), nullable=False), sa.PrimaryKeyConstraint('id') ) + op.create_table('moon', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('name', sa.String(), nullable=False), + sa.Column('size', sa.Float(), nullable=False), + sa.Column('description', sa.String(), nullable=False), + sa.Column('planet_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['planet_id'], ['planet.id'], ), + sa.PrimaryKeyConstraint('id') + ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('moon') op.drop_table('planet') # ### end Alembic commands ### diff --git a/moons_data.csv b/moons_data.csv index e69de29bb..48c93b472 100644 --- a/moons_data.csv +++ b/moons_data.csv @@ -0,0 +1,62 @@ +[ + {# Earth Moons + "description": "Earth's Moon is the only place beyond Earth where humans have set foot, so far.", + "size": 1738.1, + "name": "Moon" + }, + {# Mars Moons + "description": "Deimos is the smaller of Mars' two moons.", + "size": 3.9, + "name": "Deimos" + }, + {# Mars Moons + "description": "Phobos was discovered on Aug. 17, 1877 by Asaph Hall.v", + "size": 7.0, + "name": "Phobos" + }, + {# Jupiter Moons + "description": "Io is the most volcanically active world in the solar system.", + "size": 1821.3, + "name": "Io" + }, + {# Jupiter Moons + "description": "Europa is perhaps the most promising place to look for present-day environments suitable for life.", + "size": 1569.0, + "name": "Europa" + }, + {# Jupiter Moons + "description": "Ganymede is the largest moon in our solar system and the only moon known to create its own magnetic field.", + "size": 2634.1, + "name": "Ganymede" + }, + {# Jupiter Moons + "description": "Callisto is among the most heavily cratered objects that orbit the Sun.", + "size": 2410.3, + "name": "Callisto" + }, + {# Saturn Moons + "description": "Enceladus has the whitest, most reflective surface in the solar system.", + "size": 156.65, + "name": "Enceladus" + }, + {# Saturn Moons + "description": "Titan is the only moon in our solar system that has clouds and a dense atmosphere.", + "size": 2575.0, + "name": "Titan" + }, + {# Uranus Moons + "description": "All of Uranus' larger moons, including Ariel, are thought to consist mostly of roughly equal amounts of water ice and silicate rock.", + "size": 359.7, + "name": "Ariel" + }, + {# Uranus Moons + "description": "Oberon is the second largest moon of Uranus.", + "size": 473.1, + "name": "Oberon" + }, + {# Uranus Moons + "description": "Rosalind was discovered by the Voyager 2 science team on 13 January 1986.", + "size": 22.0, + "name": "Rosalind" + } +] \ No newline at end of file diff --git a/tests/test_models.py b/tests/test_models.py index a02817d88..e5c2bfa40 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,63 +1,118 @@ from app import db from app.models.planet import Planet +from app.models.moon import Moon import pytest def test_to_dict_no_missing_data(): # Arrange + moon1 = Moon( + description = "Earth's Moon is the only place beyond Earth where humans have set foot, so far.", + size = 1738.1, + name = "Moon" + ) + test_data = Planet( name="Test", + moons = [moon1], description="Imaginary for testing", length_of_year = 100) # Act result = test_data.to_dict() # Assert - assert len(result) == 4 + assert len(result) == 5 + assert result["moons"] == ["Moon"] assert result["name"] == "Test" assert result["length_of_year"] == 100 assert result["description"] == "Imaginary for testing" def test_to_dict_missing_id(): # Arrange + moon1 = Moon( + description = "Earth's Moon is the only place beyond Earth where humans have set foot, so far.", + size = 1738.1, + name = "Moon" + ) test_data = Planet(name="Test", description="Imaginary for testing", - length_of_year = 100 + length_of_year = 100, + moons = [moon1] ) # Act result = test_data.to_dict() # Assert - assert len(result) == 4 + assert len(result) == 5 assert result["name"] == "Test" + assert result["moons"] == ["Moon"] assert result["length_of_year"] == 100 assert result["description"] == "Imaginary for testing" def test_to_dict_missing_name(): -# Arrange + # Arrange + moon1 = Moon( + description = "Earth's Moon is the only place beyond Earth where humans have set foot, so far.", + size = 1738.1, + name = "Moon" + ) + test_data = Planet( + moons = [moon1], description="Imaginary for testing", - length_of_year = 100 - ) + length_of_year = 100) -# Act + # Act result = test_data.to_dict() -# Assert - assert len(result) == 4 + # Assert + assert len(result) == 5 + assert result["moons"] == ["Moon"] assert result["name"] == None assert result["length_of_year"] == 100 assert result["description"] == "Imaginary for testing" def test_to_dict_missing_description(): -# Arrange - test_data = Planet(name="Test", + # Arrange + moon1 = Moon( + description = "Earth's Moon is the only place beyond Earth where humans have set foot, so far.", + size = 1738.1, + name = "Moon" + ) + + test_data = Planet( + name="Test", + moons = [moon1], length_of_year = 100) -# Act + + # Act result = test_data.to_dict() -# Assert - assert len(result) == 4 + # Assert + assert len(result) == 5 + assert result["moons"] == ["Moon"] assert result["name"] == "Test" assert result["length_of_year"] == 100 assert result["description"] == None +def test_to_dict_missing_moon(): + # Arrange + moon1 = Moon( + description = "Earth's Moon is the only place beyond Earth where humans have set foot, so far.", + size = 1738.1, + name = "Moon" + ) + + test_data = Planet( + name="Test", + description="Imaginary for testing", + length_of_year = 100) + + # Act + result = test_data.to_dict() + # Assert + assert len(result) == 5 + assert result["moons"] == [] + assert result["name"] == "Test" + assert result["length_of_year"] == 100 + assert result["description"] == "Imaginary for testing" + def test_from_dict_returns_planet(): # Arrange planet_data = { @@ -97,8 +152,7 @@ def test_from_dict_with_extra_keys(): planet_data = { "name": "Test", "length_of_year": 100, - "description": "Imaginary for testing", - "number_of_moons": 9 + "description": "Imaginary for testing" } # Act new_planet = Planet.from_dict(planet_data) diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index 3191860ef..05a118505 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -193,7 +193,8 @@ def test_get_planet1_from_fixture_one_planet_return_200(client,one_planet): "id":1, "name": "Mercury", "length_of_year": 88, - "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + "moons": [] } def test_get_planet1_from_fixture_three_planet_return_200(client,three_planets): @@ -207,7 +208,8 @@ def test_get_planet1_from_fixture_three_planet_return_200(client,three_planets): "id":1, "name": "Mercury", "length_of_year": 88, - "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + "moons": [] } def test_get_planet1_no_fixture_return_404(client): @@ -232,7 +234,8 @@ def test_get_planets_in_array_return_200(client,one_planet): "id":1, "name": "Mercury", "length_of_year": 88, - "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + "moons": [] } ] @@ -249,19 +252,22 @@ def test_get_planets_in_array_with_fixture_three_planets_return_200(client,three "id":1, "name": "Mercury", "length_of_year": 88, - "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun." + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + "moons": [] }, { "id":2, "name": "Venus", "length_of_year": 225, - "description": "Venus spins slowly in the opposite direction from most planets." + "description": "Venus spins slowly in the opposite direction from most planets.", + "moons": [] }, { "id":3, "name": "Earth", "length_of_year": 365, - "description": "Earth — our home planet." + "description": "Earth — our home planet.", + "moons": [] } ] From ebd6896f83912de062e56f2d9180b83111f98656 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 5 Jan 2023 16:30:27 -0800 Subject: [PATCH 74/85] add planet_moon_routes --- app/routes/planet_routes.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index c4275a61f..9b0e056cc 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -1,5 +1,6 @@ from app import db from app.models.planet import Planet +from app.models.moon import Moon from flask import Blueprint, jsonify, abort, make_response, request planets_bp = Blueprint("planets_bp", __name__, url_prefix = "/planets") @@ -99,4 +100,28 @@ def delete_planet(planet_id): db.session.delete(planet) db.session.commit() - return make_response(jsonify(f"Planet {planet.id} successfully deleted"), 200) \ No newline at end of file + return make_response(jsonify(f"Planet {planet.id} successfully deleted"), 200) + +@planets_bp.route("//moons", methods=["POST"]) +def add_new_cat_to_caretaker(planet_id): + planet = validate_model(Planet, planet_id) + + request_body = request.get_json() + moon = Moon.from_dict(request_body) + moon.planet = planet + + db.session.add(moon) + db.session.commit() + + message = f"Cat {moon.name} created with Caretaker {planet.name}" + return make_response(jsonify(message), 201) + +@planets_bp.route("//moons", methods=["GET"]) +def get_all_moons_for_planet(planet_id): + planet = validate_model(Planet, planet_id) + + moons_response = [] + for moon in planet.moons: + moons_response.append(moon.to_dict()) + + return jsonify(moons_response) \ No newline at end of file From a9e828be59edf409a2a3201a6082b1311a9a0254 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 5 Jan 2023 17:03:50 -0800 Subject: [PATCH 75/85] refactor helper function --- app/models/moon.py | 1 - app/routes/moon_routes.py | 37 +++++++++-------------- app/routes/planet_routes.py | 56 ++++++++++++++--------------------- app/routes/validate_routes.py | 47 +++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 57 deletions(-) create mode 100644 app/routes/validate_routes.py diff --git a/app/models/moon.py b/app/models/moon.py index 36f372699..1a610a61f 100644 --- a/app/models/moon.py +++ b/app/models/moon.py @@ -16,7 +16,6 @@ def to_dict(self): moon_as_dict["description"] = self.description return moon_as_dict - @classmethod def from_dict(cls,moon_data): new_moon = Moon(name=moon_data["name"], diff --git a/app/routes/moon_routes.py b/app/routes/moon_routes.py index a17e86c64..5885a01af 100644 --- a/app/routes/moon_routes.py +++ b/app/routes/moon_routes.py @@ -2,27 +2,28 @@ from app.models.moon import Moon from app.models.planet import Planet from flask import Blueprint, jsonify, abort, make_response, request -from .planet_routes import validate_model +from .validate_routes import validate_model, validate_moon_user_input, validate_planet_user_input moons_bp = Blueprint("moons_bp", __name__, url_prefix = "/moons") #`/moons//moons` with the POST -@moons_bp.route("//moons", methods=["POST"]) -def create_moon(planet_id): +# @moons_bp.route("/moons", methods=["POST"]) +# def create_moon(planet_id): - planet = validate_model(Planet, planet_id) +# planet = validate_model(Planet, planet_id) - request_body = request.get_json() - new_moon = Moon.from_dict(request_body) - new_moon.planet = planet +# request_body = request.get_json() +# new_moon = Moon.from_dict(request_body) +# new_moon.planet = planet - db.session.add(new_moon) - db.session.commit() +# db.session.add(new_moon) +# db.session.commit() - message = f"Moon {new_moon.name} created with Planet {planet.name}" - return make_response(jsonify(message), 201) +# message = f"Moon {new_moon.name} created with Planet {planet.name}" +# return make_response(jsonify(message), 201) -# Get all moons info +# Get all moons info +# /moons # Return JSON list @moons_bp.route("", methods = ["GET"]) def get_all_moons_query(): @@ -43,14 +44,4 @@ def get_all_moons_query(): for moon in moon_query: moon_response.append(moon.to_dict()) - return jsonify(moon_response), 200 - -#/planets//moons` with the GET method -@moons_bp.route("//moons", methods=["GET"]) -def read_moons(planet_id): - planet = validate_model(Planet, planet_id) - - moons_response = [] - for moon in planet.moons: - moons_response.append(moon.to_dict()) - return jsonify(moons_response) \ No newline at end of file + return jsonify(moon_response), 200 \ No newline at end of file diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 9b0e056cc..0d6cc9567 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -1,43 +1,16 @@ from app import db from app.models.planet import Planet from app.models.moon import Moon +from .validate_routes import validate_model, validate_moon_user_input, validate_planet_user_input from flask import Blueprint, jsonify, abort, make_response, request planets_bp = Blueprint("planets_bp", __name__, url_prefix = "/planets") -# Helper functions -# Validating the id of the planet: id needs to be int and exists the planet with the id. -# Returning the valid Planet instance if valid id -def validate_model(cls, model_id): - try: - model_id = int(model_id) - except: - abort(make_response(jsonify(f"{cls.__name__} {model_id} invalid"), 400)) - class_obj = cls.query.get(model_id) - if not class_obj: - abort(make_response(jsonify(f"{cls.__name__} {model_id} not found"), 404)) - return class_obj - -# Validating the user input to create or update the table planet -# Returning the valid JSON if valid input -def validate_input(planet_value): - if "name" not in planet_value \ - or not isinstance(planet_value["name"], str) \ - or planet_value["name"] == "" \ - or "length_of_year" not in planet_value \ - or not isinstance(planet_value["length_of_year"], int) \ - or planet_value["length_of_year"] <=0 \ - or "description" not in planet_value \ - or not isinstance(planet_value["description"], str) \ - or planet_value["description"] == "": - return abort(make_response(jsonify("Invalid request"), 400)) - return planet_value - # Routes functions # Creating new record in the database Planet @planets_bp.route("", methods = ["POST"]) def create_planet(): - planet_value = validate_input(request.get_json()) + planet_value = validate_planet_user_input(request.get_json()) new_planet = Planet.from_dict(planet_value) db.session.add(new_planet) @@ -84,7 +57,7 @@ def get_one_planet(planet_id): @planets_bp.route("/",methods=["PUT"] ) def update_planet(planet_id): planet = validate_model(Planet, planet_id) - request_body = validate_input(request.get_json()) + request_body = validate_planet_user_input(request.get_json()) planet.name = request_body["name"] planet.length_of_year = request_body["length_of_year"] @@ -103,7 +76,7 @@ def delete_planet(planet_id): return make_response(jsonify(f"Planet {planet.id} successfully deleted"), 200) @planets_bp.route("//moons", methods=["POST"]) -def add_new_cat_to_caretaker(planet_id): +def add_new_moon_to_planet(planet_id): planet = validate_model(Planet, planet_id) request_body = request.get_json() @@ -113,7 +86,7 @@ def add_new_cat_to_caretaker(planet_id): db.session.add(moon) db.session.commit() - message = f"Cat {moon.name} created with Caretaker {planet.name}" + message = f"Moon {moon.name} added to the planet {planet.name}." return make_response(jsonify(message), 201) @planets_bp.route("//moons", methods=["GET"]) @@ -124,4 +97,21 @@ def get_all_moons_for_planet(planet_id): for moon in planet.moons: moons_response.append(moon.to_dict()) - return jsonify(moons_response) \ No newline at end of file + return jsonify(moons_response) + +### update moon info of the planet with provided id +@planets_bp.route("//moons/", methods=["POST"]) +def update_moon_of_planet(planet_id, moon_id): + planet = validate_model(Planet, planet_id) + moon = validate_model(Moon, moon_id) + + request_body = validate_moon_user_input(request.get_json()) + + moon.name = request_body["name"] + moon.size = request_body["size"] + moon.description = request_body["description"] + + db.session.commit() + + message = f"Moon {moon.name} added to the planet {planet.name}." + return make_response(jsonify(message), 201) \ No newline at end of file diff --git a/app/routes/validate_routes.py b/app/routes/validate_routes.py new file mode 100644 index 000000000..5fba32f1a --- /dev/null +++ b/app/routes/validate_routes.py @@ -0,0 +1,47 @@ +from app import db +from app.models.planet import Planet +from app.models.moon import Moon +from flask import Blueprint, jsonify, abort, make_response, request + +# Validating the id of the instance: id needs to be int and exists the instance with the id. +# Returning the valid Class instance if valid id +# Work for Planet and Moon classes +def validate_model(cls, model_id): + try: + model_id = int(model_id) + except: + abort(make_response(jsonify(f"{cls.__name__} {model_id} invalid"), 400)) + class_obj = cls.query.get(model_id) + if not class_obj: + abort(make_response(jsonify(f"{cls.__name__} {model_id} not found"), 404)) + return class_obj + +# Validating the user input to create or update the table planet +# Returning the valid JSON if valid input +def validate_planet_user_input(planet_value): + if "name" not in planet_value \ + or not isinstance(planet_value["name"], str) \ + or planet_value["name"] == "" \ + or "length_of_year" not in planet_value \ + or not isinstance(planet_value["length_of_year"], int) \ + or planet_value["length_of_year"] <=0 \ + or "description" not in planet_value \ + or not isinstance(planet_value["description"], str) \ + or planet_value["description"] == "": + return abort(make_response(jsonify("Invalid request"), 400)) + return planet_value + +# Validating the user input to create or update the table moon +# Returning the valid JSON if valid input +def validate_moon_user_input(moon_value): + if "name" not in moon_value \ + or not isinstance(moon_value["name"], str) \ + or moon_value["name"] == "" \ + or "size" not in moon_value \ + or not isinstance(moon_value["size"], float) \ + or moon_value["size"] <0 \ + or "description" not in moon_value \ + or not isinstance(moon_value["description"], str) \ + or moon_value["description"] == "": + return abort(make_response(jsonify("Invalid request"), 400)) + return moon_value \ No newline at end of file From 8faedbe5af4c153c5f58c31767a887dd4e12eb3c Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 5 Jan 2023 18:36:05 -0800 Subject: [PATCH 76/85] added moon_routes and planet_routes --- app/models/moon.py | 1 + app/routes/moon_routes.py | 48 +++++++++++++++++++++---------------- app/routes/planet_routes.py | 47 +++++++++++++++++++++++++++++++----- moons_data.csv | 12 ++++++++++ planets_data.csv | 12 ++++++++++ 5 files changed, 93 insertions(+), 27 deletions(-) diff --git a/app/models/moon.py b/app/models/moon.py index 1a610a61f..1870a735a 100644 --- a/app/models/moon.py +++ b/app/models/moon.py @@ -14,6 +14,7 @@ def to_dict(self): moon_as_dict["name"] = self.name moon_as_dict["size"] = self.size moon_as_dict["description"] = self.description + moon_as_dict["planet_id"] = self.planet_id return moon_as_dict @classmethod diff --git a/app/routes/moon_routes.py b/app/routes/moon_routes.py index 5885a01af..e91464edb 100644 --- a/app/routes/moon_routes.py +++ b/app/routes/moon_routes.py @@ -6,42 +6,48 @@ moons_bp = Blueprint("moons_bp", __name__, url_prefix = "/moons") -#`/moons//moons` with the POST -# @moons_bp.route("/moons", methods=["POST"]) -# def create_moon(planet_id): - -# planet = validate_model(Planet, planet_id) - -# request_body = request.get_json() -# new_moon = Moon.from_dict(request_body) -# new_moon.planet = planet - -# db.session.add(new_moon) -# db.session.commit() - -# message = f"Moon {new_moon.name} created with Planet {planet.name}" -# return make_response(jsonify(message), 201) - # Get all moons info # /moons # Return JSON list @moons_bp.route("", methods = ["GET"]) def get_all_moons_query(): moon_query = Moon.query - # Filtering by name (return all records which name contains planet_name_query) + # Filtering by moon name (return all records which name contains planet_name_query) moon_name_query = request.args.get("name") - if moon_name_query: moon_query = moon_query.filter(Moon.name.ilike(f"%{moon_name_query}%")) - + # Sorting by moon name sort_by_name_query = request.args.get("sort_by_name") if sort_by_name_query == "desc": moon_query = moon_query.order_by(Moon.name.desc()).all() elif sort_by_name_query == "asc": - moon_query = moon_query.order_by(Moon.name).all() + moon_query = moon_query.order_by(Moon.name).all() + + # Sorting by moon size + moon_sort_size_query = request.args.get("sort_by_size") + if moon_sort_size_query == "desc": + moon_query = moon_query.order_by(Moon.size.desc()).all() + elif sort_by_name_query == "asc": + moon_query = moon_query.order_by(Moon.size).all() moon_response = [] for moon in moon_query: moon_response.append(moon.to_dict()) - return jsonify(moon_response), 200 \ No newline at end of file + return jsonify(moon_response), 200 + +# Read one moon +# Return one moon info in JSON format +@moons_bp.route("/",methods=["GET"] ) +def get_one_moon(moon_id): + moon = validate_model(Moon, moon_id) + return moon.to_dict() + +# Delete moon by id +@moons_bp.route("/",methods=["DELETE"]) +def delete_moon(moon_id): + moon = validate_model(Moon, moon_id) + db.session.delete(moon) + db.session.commit() + + return make_response(jsonify(f"Planet {moon.id} successfully deleted"), 200) \ No newline at end of file diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 0d6cc9567..93da287fc 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -7,7 +7,7 @@ planets_bp = Blueprint("planets_bp", __name__, url_prefix = "/planets") # Routes functions -# Creating new record in the database Planet +# Creating new planet @planets_bp.route("", methods = ["POST"]) def create_planet(): planet_value = validate_planet_user_input(request.get_json()) @@ -64,24 +64,36 @@ def update_planet(planet_id): planet.description = request_body["description"] db.session.commit() - return make_response(jsonify(f"Planet {planet_id} successfully updated"), 200) + message = f"Planet {planet_id} successfully updated" + return make_response(jsonify(message), 200) -# Delete one planet +# Delete one planet and all the moons dependent of the planet @planets_bp.route("/",methods=["DELETE"]) def delete_planet(planet_id): planet = validate_model(Planet, planet_id) + if len(planet.moons)>0: + i = 0 + while i < len(planet.moons): + moon_id = planet.moons[i].id + moon = validate_model(Moon, moon_id) + db.session.delete(moon) + db.session.commit() + i += 1 + db.session.delete(planet) db.session.commit() return make_response(jsonify(f"Planet {planet.id} successfully deleted"), 200) +# Add moon info to the planet using planet id @planets_bp.route("//moons", methods=["POST"]) def add_new_moon_to_planet(planet_id): planet = validate_model(Planet, planet_id) request_body = request.get_json() moon = Moon.from_dict(request_body) - moon.planet = planet + #moon.planet = planet + moon.planet_id = planet_id db.session.add(moon) db.session.commit() @@ -89,6 +101,7 @@ def add_new_moon_to_planet(planet_id): message = f"Moon {moon.name} added to the planet {planet.name}." return make_response(jsonify(message), 201) +# Get all moons info for chosen planet (by planet id) @planets_bp.route("//moons", methods=["GET"]) def get_all_moons_for_planet(planet_id): planet = validate_model(Planet, planet_id) @@ -99,9 +112,18 @@ def get_all_moons_for_planet(planet_id): return jsonify(moons_response) -### update moon info of the planet with provided id +# Get moon by id +# Return one moon info in JSON format +@planets_bp.route("//moons/",methods=["GET"] ) +def get_one_moon(planet_id, moon_id): + planet = validate_model(Planet, planet_id) + moon = validate_model(Planet, moon_id) + return moon.to_dict() + +# Update moon info (by moon_id) of the planet using planet_id @planets_bp.route("//moons/", methods=["POST"]) def update_moon_of_planet(planet_id, moon_id): + planet = validate_model(Planet, planet_id) moon = validate_model(Moon, moon_id) @@ -113,5 +135,18 @@ def update_moon_of_planet(planet_id, moon_id): db.session.commit() - message = f"Moon {moon.name} added to the planet {planet.name}." + message = f"Moon {moon.id} of the planet {planet.name} successfully updated." + return make_response(jsonify(message), 201) + +# Delete moon of the specific planet (using planet_id and moon_id) +@planets_bp.route("//moons/", methods=["DELETE"]) +def delete_moon_of_planet(planet_id, moon_id): + + planet = validate_model(Planet, planet_id) + moon = validate_model(Moon, moon_id) + + db.session.delete(moon) + db.session.commit() + + message = f"Moon {moon.id} of the planet {planet.name} successfully deleted." return make_response(jsonify(message), 201) \ No newline at end of file diff --git a/moons_data.csv b/moons_data.csv index 48c93b472..4542ba306 100644 --- a/moons_data.csv +++ b/moons_data.csv @@ -59,4 +59,16 @@ "size": 22.0, "name": "Rosalind" } + + #### For Testing + { + "description": "Moon for testing purpose.", + "size": 7000, + "name": "Moon_Test1" + }, + { + "description": "Moon just for testing.", + "size": 6, + "name": "Moon_Test2" + } ] \ No newline at end of file diff --git a/planets_data.csv b/planets_data.csv index 34df10aff..426c31d26 100644 --- a/planets_data.csv +++ b/planets_data.csv @@ -39,4 +39,16 @@ "length_of_year": 60190, "name": "Neptune" } + +#### For Testing + { + "description": "Imaginary planet for testing purpose.", + "length_of_year": 7000, + "name": "Planet_Test1" + }, + { + "description": "Just for testing.", + "length_of_year": 6, + "name": "Planet_Test2" + } ] \ No newline at end of file From 6436d7b9da074ab0315a928a902acff51c7afd2d Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 5 Jan 2023 19:56:36 -0800 Subject: [PATCH 77/85] added feature: delete all moons of the deleted planet. --- tests/conftest.py | 24 ++++++++++++++++++++++++ tests/test_models.py | 30 +++++++++++++++++++++++++++++- tests/test_planet_routes.py | 36 ++++++++++-------------------------- 3 files changed, 63 insertions(+), 27 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 6c59e90f3..5c3f31fd3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,7 @@ from app import create_app, db from flask.signals import request_finished from app.models.planet import Planet +from app.models.moon import Moon @pytest.fixture def app(): @@ -35,6 +36,29 @@ def one_planet(app): db.session.refresh(planet, ["id"]) return planet +@pytest.fixture +def one_planet_with_moons(app): + moon1 = Moon( + description = "Moon for testing purpose.", + size = 173.1, + name = "Moon_Test1" + ) + moon2 = Moon( + description = "Moon just for testing.", + size = 17, + name = "Moon_Test2" + ) + planet = Planet( + name = "Mercury", + description = "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + length_of_year = 88, + moons = [moon1, moon2]) + + db.session.add(planet) + db.session.commit() + db.session.refresh(planet, ["id"]) + return planet + @pytest.fixture def three_planets(app): planet_mercury = Planet( diff --git a/tests/test_models.py b/tests/test_models.py index e5c2bfa40..1656dea4c 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,6 +1,8 @@ from app import db from app.models.planet import Planet from app.models.moon import Moon +from app.routes.planet_routes import validate_model +from werkzeug.exceptions import HTTPException import pytest def test_to_dict_no_missing_data(): @@ -159,4 +161,30 @@ def test_from_dict_with_extra_keys(): # Assert assert new_planet.name == "Test" assert new_planet.length_of_year == 100 - assert new_planet.description == "Imaginary for testing" \ No newline at end of file + assert new_planet.description == "Imaginary for testing" + +#### tests for validate_model #### +def test_validate_model(three_planets): + # Act + result_planet = validate_model(Planet, 1) + # Assert + assert result_planet.id == 1 + assert result_planet.name == "Mercury" + assert result_planet.length_of_year == 88 + assert result_planet.description == "Mercury is the smallest planet in the Solar System and the closest to the Sun." + +def test_validate_model_missing_record(three_planets): + # Act & Assert + # Calling `validate_book` without being invoked by a route will + # cause an `HTTPException` when an `abort` statement is reached + with pytest.raises(HTTPException): + result_planet = validate_model(Planet, 9) + +def test_validate_model_invalid_id(three_planets): + # Act & Assert + # Calling `validate_book` without being invoked by a route will + # cause an `HTTPException` when an `abort` statement is reached + with pytest.raises(HTTPException): + result_planet = validate_model(Planet, "hello") + +#### tests for validate_input #### \ No newline at end of file diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index 05a118505..c3cdeaaaa 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -155,7 +155,7 @@ def test_update_planet_invalid_request_description_empty(client, one_planet): assert response_body == "Invalid request" #### DELETE #### -def test_delete_planet_by_id_valid_request(client, one_planet): +def test_delete_planet_by_id_valid_request_with_zero_moons(client, one_planet): # Act planet_id = one_planet.id response = client.delete(f"/planets/{planet_id}") @@ -164,6 +164,15 @@ def test_delete_planet_by_id_valid_request(client, one_planet): assert response.status_code == 200 assert response_body == f"Planet {planet_id} successfully deleted" +def test_delete_planet_by_id_valid_request_with_two_moons(client, one_planet_with_moons): + # Act + planet_id = one_planet_with_moons.id + response = client.delete(f"/planets/{planet_id}") + response_body = response.get_json() + # Assert + assert response.status_code == 200 + assert response_body == f"Planet {planet_id} successfully deleted" + def test_delete_planet_by_id_invalid_id(client, one_planet): # Act planet_id = "hello" @@ -271,28 +280,3 @@ def test_get_planets_in_array_with_fixture_three_planets_return_200(client,three } ] -#### tests for validate_model #### -def test_validate_model(three_planets): - # Act - result_planet = validate_model(Planet, 1) - # Assert - assert result_planet.id == 1 - assert result_planet.name == "Mercury" - assert result_planet.length_of_year == 88 - assert result_planet.description == "Mercury is the smallest planet in the Solar System and the closest to the Sun." - -def test_validate_model_missing_record(three_planets): - # Act & Assert - # Calling `validate_book` without being invoked by a route will - # cause an `HTTPException` when an `abort` statement is reached - with pytest.raises(HTTPException): - result_planet = validate_model(Planet, 9) - -def test_validate_model_invalid_id(three_planets): - # Act & Assert - # Calling `validate_book` without being invoked by a route will - # cause an `HTTPException` when an `abort` statement is reached - with pytest.raises(HTTPException): - result_planet = validate_model(Planet, "hello") - -#### tests for validate_input #### From bc1be3b31bc664e061bb408862eaca3ecb440aa2 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Thu, 5 Jan 2023 20:34:42 -0800 Subject: [PATCH 78/85] Complite Wave 08 --- app/models/moon.py | 3 ++- app/routes/moon_routes.py | 10 ++++++++++ app/routes/planet_routes.py | 4 ++-- app/routes/validate_routes.py | 7 +++++-- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/models/moon.py b/app/models/moon.py index 1870a735a..4560dfd5b 100644 --- a/app/models/moon.py +++ b/app/models/moon.py @@ -21,5 +21,6 @@ def to_dict(self): def from_dict(cls,moon_data): new_moon = Moon(name=moon_data["name"], size=float(moon_data["size"]), - description=moon_data["description"]) + description=moon_data["description"], + planet_id = int(moon_data["planet_id"]))#### return new_moon \ No newline at end of file diff --git a/app/routes/moon_routes.py b/app/routes/moon_routes.py index e91464edb..15e3e535b 100644 --- a/app/routes/moon_routes.py +++ b/app/routes/moon_routes.py @@ -43,6 +43,16 @@ def get_one_moon(moon_id): moon = validate_model(Moon, moon_id) return moon.to_dict() +# Create one moon +@moons_bp.route("", methods = ["POST"]) +def create_moon(): + moon_value = validate_moon_user_input(request.get_json()) + new_moon = Moon.from_dict(moon_value) + + db.session.add(new_moon) + db.session.commit() + return make_response(jsonify(f"Moon {new_moon.name} successfully created"), 201) + # Delete moon by id @moons_bp.route("/",methods=["DELETE"]) def delete_moon(moon_id): diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 93da287fc..09b330af9 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -114,10 +114,10 @@ def get_all_moons_for_planet(planet_id): # Get moon by id # Return one moon info in JSON format -@planets_bp.route("//moons/",methods=["GET"] ) +@planets_bp.route("//moons/",methods=["GET"] ) def get_one_moon(planet_id, moon_id): planet = validate_model(Planet, planet_id) - moon = validate_model(Planet, moon_id) + moon = validate_model(Moon, moon_id) return moon.to_dict() # Update moon info (by moon_id) of the planet using planet_id diff --git a/app/routes/validate_routes.py b/app/routes/validate_routes.py index 5fba32f1a..7691ba981 100644 --- a/app/routes/validate_routes.py +++ b/app/routes/validate_routes.py @@ -34,14 +34,17 @@ def validate_planet_user_input(planet_value): # Validating the user input to create or update the table moon # Returning the valid JSON if valid input def validate_moon_user_input(moon_value): + + if not "planet_id": moon_value["planet_id"] = 0 #### + if "name" not in moon_value \ or not isinstance(moon_value["name"], str) \ or moon_value["name"] == "" \ or "size" not in moon_value \ - or not isinstance(moon_value["size"], float) \ + or not (isinstance(moon_value["size"], float) or isinstance(moon_value["size"], int)) \ or moon_value["size"] <0 \ or "description" not in moon_value \ or not isinstance(moon_value["description"], str) \ or moon_value["description"] == "": - return abort(make_response(jsonify("Invalid request"), 400)) + return abort(make_response(jsonify("Invalid request"), 400)) return moon_value \ No newline at end of file From 8b25f44aeb9423dfa6f71e53c449b9822aa2a267 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Sat, 7 Jan 2023 21:07:35 -0800 Subject: [PATCH 79/85] update tests --- app/models/moon.py | 2 +- app/routes/planet_routes.py | 3 +- tests/conftest.py | 45 +++++- tests/test_moon_routes.py | 285 ++++++++++++++++++++++++++++++++++++ tests/test_planet_routes.py | 131 ++++++++++++----- 5 files changed, 424 insertions(+), 42 deletions(-) diff --git a/app/models/moon.py b/app/models/moon.py index 4560dfd5b..03bb12990 100644 --- a/app/models/moon.py +++ b/app/models/moon.py @@ -22,5 +22,5 @@ def from_dict(cls,moon_data): new_moon = Moon(name=moon_data["name"], size=float(moon_data["size"]), description=moon_data["description"], - planet_id = int(moon_data["planet_id"]))#### + planet_id = int(moon_data["planet_id"])) return new_moon \ No newline at end of file diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 09b330af9..83785132f 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -6,7 +6,6 @@ planets_bp = Blueprint("planets_bp", __name__, url_prefix = "/planets") -# Routes functions # Creating new planet @planets_bp.route("", methods = ["POST"]) def create_planet(): @@ -115,7 +114,7 @@ def get_all_moons_for_planet(planet_id): # Get moon by id # Return one moon info in JSON format @planets_bp.route("//moons/",methods=["GET"] ) -def get_one_moon(planet_id, moon_id): +def get_one_moon_of_planet(planet_id, moon_id): planet = validate_model(Planet, planet_id) moon = validate_model(Moon, moon_id) return moon.to_dict() diff --git a/tests/conftest.py b/tests/conftest.py index 5c3f31fd3..404fee80a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -48,16 +48,16 @@ def one_planet_with_moons(app): size = 17, name = "Moon_Test2" ) - planet = Planet( + planet_mercury = Planet( name = "Mercury", description = "Mercury is the smallest planet in the Solar System and the closest to the Sun.", length_of_year = 88, moons = [moon1, moon2]) - db.session.add(planet) + db.session.add(planet_mercury) db.session.commit() - db.session.refresh(planet, ["id"]) - return planet + db.session.refresh(planet_mercury, ["id"]) + return planet_mercury @pytest.fixture def three_planets(app): @@ -77,3 +77,40 @@ def three_planets(app): db.session.add_all([planet_mercury, planet_venus, planet_earth]) db.session.commit() +@pytest.fixture +def three_planets_with_moons(app): + moon1 = Moon( + description = "Moon1 for testing purpose.", + size = 173.1, + name = "Moon_Test1") + moon2 = Moon( + description = "Moon2 just for testing.", + size = 17, + name = "Moon_Test2") + moon3 = Moon( + description = "Moon3 for testing purpose.", + size = 11, + name = "Moon_Test3") + moon4 = Moon( + description = "Moon4 just for testing.", + size = 19, + name = "Moon_Test4") + + planet_mercury = Planet( + name = "Mercury", + description = "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + length_of_year = 88, + moons = [moon1, moon2]) + planet_venus = Planet( + name = "Venus", + description = "Venus spins slowly in the opposite direction from most planets.", + length_of_year = 225, + moons = [moon3]) + planet_earth = Planet( + name = "Earth", + description = "Earth — our home planet.", + length_of_year = 365, + moons = [moon4]) + + db.session.add_all([planet_mercury, planet_venus, planet_earth]) + db.session.commit() \ No newline at end of file diff --git a/tests/test_moon_routes.py b/tests/test_moon_routes.py index e69de29bb..15e293027 100644 --- a/tests/test_moon_routes.py +++ b/tests/test_moon_routes.py @@ -0,0 +1,285 @@ +from werkzeug.exceptions import HTTPException +from app.models.moon import Moon +import pytest + +#### POST/ Create moon #### +def test_create_moon_valid_request_return_200(client): # return ""Moon {new_moon.name} successfully created", 201 + # Act + response = client.post("/moons", json = { + "description": "Fantasy moon for testing purpose.", + "name": "Test1", + "size": 3.6, + "planet_id": + }) + response_body = response.get_json() + + # Assert + assert response.status_code == 201 + assert response_body == "Planet Mars successfully created" + +def test_create_planet_invalid_request_empty_name(client): + # Act + response = client.post("/planets", json = { + "name": "", + "description": "This unknown planet is the imaginary planet for purpose of testing.", + "length_of_year": 10}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +def test_create_planet_invalid_request_lenght_of_year_zero(client): + # Act + response = client.post("/planets", json = { + "name": "Test", + "description": "This unknown planet is the imaginary planet for purpose of testing.", + "length_of_year": 0}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +def test_create_planet_invalid_request_lenght_of_year_negative(client): + # Act + response = client.post("/planets", json = { + 'name': 'Test', + 'description': 'This unknown planet is the imaginary planet for purpose of testing.', + 'length_of_year': -100}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +def test_create_planet_invalid_request_description_empty(client): + # Act + response = client.post("/planets", json = { + 'name': 'Test', + 'description': '', + 'length_of_year': 10}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +#### PUT #### +def test_update_planet_valid_request(client, one_planet): + # Act + planet_id = one_planet.id + response = client.put(f"/planets/{one_planet.id}", json = { + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + "length_of_year": 88, + "name": "Mercury_updated" + }) + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == f"Planet {planet_id} successfully updated" + +def test_update_planet_not_exist_id(client, one_planet): + # Act + response = client.put("/planets/9", json = { + "description": "Mars is a dusty, cold, desert world with a very thin atmosphere.", + "length_of_year": 687, + "name": "Mars" + }) + response_body = response.get_json() + + # Assert + assert response.status_code == 404 + assert response_body == f"Planet 9 not found" + +def test_update_planet_invalid_type_id(client, one_planet): + # Act + planet_id = "hello" + response = client.put(f"/planets/{planet_id}", json = { + "description": "Mars is a dusty, cold, desert world with a very thin atmosphere.", + "length_of_year": 687, + "name": "Mars" + }) + response_body = response.get_json() + # Assert + assert response.status_code == 400 + assert response_body == f"Planet {planet_id} invalid" + +def test_update_planet_invalid_request_empty_name(client, one_planet): + # Act + response = client.put(f"/planets/{one_planet.id}", json = { + "name": "", + "description": "This unknown planet is the imaginary planet for purpose of testing.", + "length_of_year": 10}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +def test_update_planet_invalid_request_lenght_of_year_zero(client, one_planet): + # Act + response = client.put(f"/planets/{one_planet.id}", json = { + "name": "Test", + "description": "This unknown planet is the imaginary planet for purpose of testing.", + "length_of_year": 0}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +def test_update_planet_invalid_request_lenght_of_year_negative(client, one_planet): + # Act + response = client.put(f"/planets/{one_planet.id}", json = { + 'name': 'Test', + 'description': 'This unknown planet is the imaginary planet for purpose of testing.', + 'length_of_year': -100}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +def test_update_planet_invalid_request_description_empty(client, one_planet): + # Act + response = client.put(f"/planets/{one_planet.id}", json = { + 'name': 'Test', + 'description': '', + 'length_of_year': 10}) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +#### DELETE #### +def test_delete_planet_by_id_valid_request_with_zero_moons(client, one_planet): + # Act + planet_id = one_planet.id + response = client.delete(f"/planets/{planet_id}") + response_body = response.get_json() + # Assert + assert response.status_code == 200 + assert response_body == f"Planet {planet_id} successfully deleted" + +def test_delete_planet_by_id_valid_request_with_two_moons(client, one_planet_with_moons): + # Act + planet_id = one_planet_with_moons.id + response = client.delete(f"/planets/{planet_id}") + response_body = response.get_json() + # Assert + assert response.status_code == 200 + assert response_body == f"Planet {planet_id} successfully deleted" + # Would like to add assert to check that moons deleted too + # dont know how + # will be happy to recieve the feedback :) + +def test_delete_planet_by_id_invalid_id(client, one_planet): + # Act + planet_id = "hello" + response = client.delete(f"/planets/{planet_id}") + response_body = response.get_json() + # Assert + assert response.status_code == 400 + assert response_body == f"Planet {planet_id} invalid" + +def test_delete_planet_by_not_existed_id(client, one_planet): + planet_id = 9 + response = client.delete(f"/planets/{planet_id}") + response_body = response.get_json() + # Assert + assert response.status_code == 404 + assert response_body == f"Planet {planet_id} not found" + +####GET#### +def test_get_planet1_from_fixture_one_planet_return_200(client,one_planet): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + "moons": [] + } + +def test_get_planet1_from_fixture_three_planet_return_200(client,three_planets): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + "moons": [] + } + +def test_get_planet1_no_fixture_return_404(client): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 404 + assert response_body == "Planet 1 not found" + +def test_get_planets_in_array_return_200(client,one_planet): + # Act + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert len(response_body) == 1 + assert response_body == [ + { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + "moons": [] + } + ] + +def test_get_planets_in_array_with_fixture_three_planets_return_200(client,three_planets): + # Act + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert len(response_body) == 3 + assert response_body == [ + { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + "moons": [] + }, + { + "id":2, + "name": "Venus", + "length_of_year": 225, + "description": "Venus spins slowly in the opposite direction from most planets.", + "moons": [] + }, + { + "id":3, + "name": "Earth", + "length_of_year": 365, + "description": "Earth — our home planet.", + "moons": [] + } +] + diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index c3cdeaaaa..c6fb1b382 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -1,9 +1,8 @@ from werkzeug.exceptions import HTTPException -from app.routes.planet_routes import validate_model from app.models.planet import Planet import pytest -#### POST #### +#### POST/ Create planet #### def test_create_planet_valid_request(client): # Act response = client.post("/planets", json = { @@ -65,8 +64,8 @@ def test_create_planet_invalid_request_description_empty(client): assert response.status_code == 400 assert response_body == "Invalid request" -#### PUT #### -def test_update_planet_valid_request(client, one_planet): +#### PUT/ Update planet #### +def test_update_planet_valid_request_return_success_message(client, one_planet): # Act planet_id = one_planet.id response = client.put(f"/planets/{one_planet.id}", json = { @@ -80,7 +79,7 @@ def test_update_planet_valid_request(client, one_planet): assert response.status_code == 200 assert response_body == f"Planet {planet_id} successfully updated" -def test_update_planet_not_exist_id(client, one_planet): +def test_update_planet_not_exist_id_return_404(client, one_planet): # Act response = client.put("/planets/9", json = { "description": "Mars is a dusty, cold, desert world with a very thin atmosphere.", @@ -93,7 +92,7 @@ def test_update_planet_not_exist_id(client, one_planet): assert response.status_code == 404 assert response_body == f"Planet 9 not found" -def test_update_planet_invalid_type_id(client, one_planet): +def test_update_planet_invalid_type_id_return_400(client, one_planet): # Act planet_id = "hello" response = client.put(f"/planets/{planet_id}", json = { @@ -106,7 +105,7 @@ def test_update_planet_invalid_type_id(client, one_planet): assert response.status_code == 400 assert response_body == f"Planet {planet_id} invalid" -def test_update_planet_invalid_request_empty_name(client, one_planet): +def test_update_planet_invalid_request_empty_name_return_400(client, one_planet): # Act response = client.put(f"/planets/{one_planet.id}", json = { "name": "", @@ -118,7 +117,7 @@ def test_update_planet_invalid_request_empty_name(client, one_planet): assert response.status_code == 400 assert response_body == "Invalid request" -def test_update_planet_invalid_request_lenght_of_year_zero(client, one_planet): +def test_update_planet_invalid_request_lenght_of_year_zero_return_400(client, one_planet): # Act response = client.put(f"/planets/{one_planet.id}", json = { "name": "Test", @@ -130,7 +129,7 @@ def test_update_planet_invalid_request_lenght_of_year_zero(client, one_planet): assert response.status_code == 400 assert response_body == "Invalid request" -def test_update_planet_invalid_request_lenght_of_year_negative(client, one_planet): +def test_update_planet_invalid_request_lenght_of_year_negative_return_400(client, one_planet): # Act response = client.put(f"/planets/{one_planet.id}", json = { 'name': 'Test', @@ -142,7 +141,7 @@ def test_update_planet_invalid_request_lenght_of_year_negative(client, one_plane assert response.status_code == 400 assert response_body == "Invalid request" -def test_update_planet_invalid_request_description_empty(client, one_planet): +def test_update_planet_invalid_request_description_empty_return_400(client, one_planet): # Act response = client.put(f"/planets/{one_planet.id}", json = { 'name': 'Test', @@ -154,8 +153,8 @@ def test_update_planet_invalid_request_description_empty(client, one_planet): assert response.status_code == 400 assert response_body == "Invalid request" -#### DELETE #### -def test_delete_planet_by_id_valid_request_with_zero_moons(client, one_planet): +#### DELETE/ Delete planet #### +def test_delete_planet_by_id_valid_request_with_zero_moons_return_success_message(client, one_planet): # Act planet_id = one_planet.id response = client.delete(f"/planets/{planet_id}") @@ -164,7 +163,7 @@ def test_delete_planet_by_id_valid_request_with_zero_moons(client, one_planet): assert response.status_code == 200 assert response_body == f"Planet {planet_id} successfully deleted" -def test_delete_planet_by_id_valid_request_with_two_moons(client, one_planet_with_moons): +def test_delete_planet_by_id_valid_request_with_two_moons_return_success_message(client, one_planet_with_moons): # Act planet_id = one_planet_with_moons.id response = client.delete(f"/planets/{planet_id}") @@ -172,8 +171,11 @@ def test_delete_planet_by_id_valid_request_with_two_moons(client, one_planet_wit # Assert assert response.status_code == 200 assert response_body == f"Planet {planet_id} successfully deleted" + # Would like to add assert to check that moons deleted too + # dont know how + # will be happy to recieve the feedback :) -def test_delete_planet_by_id_invalid_id(client, one_planet): +def test_delete_planet_by_invalid_type_id_return_400(client, one_planet): # Act planet_id = "hello" response = client.delete(f"/planets/{planet_id}") @@ -182,7 +184,7 @@ def test_delete_planet_by_id_invalid_id(client, one_planet): assert response.status_code == 400 assert response_body == f"Planet {planet_id} invalid" -def test_delete_planet_by_not_existed_id(client, one_planet): +def test_delete_planet_by_not_existed_id_return_404(client, one_planet): planet_id = 9 response = client.delete(f"/planets/{planet_id}") response_body = response.get_json() @@ -190,8 +192,27 @@ def test_delete_planet_by_not_existed_id(client, one_planet): assert response.status_code == 404 assert response_body == f"Planet {planet_id} not found" -####GET#### -def test_get_planet1_from_fixture_one_planet_return_200(client,one_planet): +#### GET/ Read one planet #### +def test_get_planet_not_exist_id_return_404(client,one_planet): + # Act + response = client.get("/planets/2") + response_body = response.get_json() + + # Assert + assert response.status_code == 404 + assert response_body == f"Planet 2 not found" + +def test_get_planet_invalid_type_id_return_400(client,one_planet): + # Act + planet_id = "hello" + response = client.get(f"/planets/{planet_id}") + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == f"Planet {planet_id} invalid" + +def test_get_planet_without_moons_valid_id_return_planet_info(client,three_planets): # Act response = client.get("/planets/1") response_body = response.get_json() @@ -206,9 +227,10 @@ def test_get_planet1_from_fixture_one_planet_return_200(client,one_planet): "moons": [] } -def test_get_planet1_from_fixture_three_planet_return_200(client,three_planets): +def test_get_planet_with_moon_valid_id_return_planet_info(client,one_planet_with_moons): # Act - response = client.get("/planets/1") + planet_id = one_planet_with_moons.id + response = client.get(f"/planets/{planet_id}") response_body = response.get_json() # Assert @@ -218,39 +240,79 @@ def test_get_planet1_from_fixture_three_planet_return_200(client,three_planets): "name": "Mercury", "length_of_year": 88, "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", - "moons": [] + "moons": ["Moon_Test1", "Moon_Test2"] } -def test_get_planet1_no_fixture_return_404(client): +#### GET/ Read all planets #### +def test_get_all_planets_without_moons_return_planets_info(client,three_planets): # Act - response = client.get("/planets/1") + response = client.get("/planets") response_body = response.get_json() # Assert - assert response.status_code == 404 - assert response_body == "Planet 1 not found" + assert response.status_code == 200 + assert len(response_body) == 3 + assert response_body == [ + { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + "moons": [] + }, + { + "id":2, + "name": "Venus", + "length_of_year": 225, + "description": "Venus spins slowly in the opposite direction from most planets.", + "moons": [] + }, + { + "id":3, + "name": "Earth", + "length_of_year": 365, + "description": "Earth — our home planet.", + "moons": [] + } +] -def test_get_planets_in_array_return_200(client,one_planet): +def test_get_all_planets_with_moons_return_planets_info(client,three_planets_with_moons): # Act response = client.get("/planets") response_body = response.get_json() # Assert assert response.status_code == 200 - assert len(response_body) == 1 + assert len(response_body) == 3 assert response_body == [ { "id":1, "name": "Mercury", "length_of_year": 88, "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", - "moons": [] + "moons": ["Moon_Test1", "Moon_Test2"] + }, + { + "id":2, + "name": "Venus", + "length_of_year": 225, + "description": "Venus spins slowly in the opposite direction from most planets.", + "moons": ["Moon_Test3"] + }, + { + "id":3, + "name": "Earth", + "length_of_year": 365, + "description": "Earth — our home planet.", + "moons": ["Moon_Test4"] } - ] +] -def test_get_planets_in_array_with_fixture_three_planets_return_200(client,three_planets): +def test_get_all_planets_with_moons_sorted_by_name_return_planets_info(client,three_planets_with_moons): # Act - response = client.get("/planets") + data = {"sort_by_name"} + # Act + response = client.get("/planets", query_string = data) response_body = response.get_json() # Assert @@ -262,21 +324,20 @@ def test_get_planets_in_array_with_fixture_three_planets_return_200(client,three "name": "Mercury", "length_of_year": 88, "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", - "moons": [] + "moons": ["Moon_Test1", "Moon_Test2"] }, { "id":2, "name": "Venus", "length_of_year": 225, "description": "Venus spins slowly in the opposite direction from most planets.", - "moons": [] + "moons": ["Moon_Test3"] }, { "id":3, "name": "Earth", "length_of_year": 365, "description": "Earth — our home planet.", - "moons": [] + "moons": ["Moon_Test4"] } -] - +] \ No newline at end of file From bc591e5655664d43f3e41a6c76ff245a1741a9b7 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Sat, 7 Jan 2023 22:32:50 -0800 Subject: [PATCH 80/85] added moon tests --- app/models/moon.py | 6 +- app/routes/moon_routes.py | 2 +- app/routes/validate_routes.py | 2 +- tests/conftest.py | 33 ++++- tests/test_moon_routes.py | 272 ++++++++-------------------------- tests/test_planet_routes.py | 32 ++-- 6 files changed, 118 insertions(+), 229 deletions(-) diff --git a/app/models/moon.py b/app/models/moon.py index 03bb12990..c26b1b235 100644 --- a/app/models/moon.py +++ b/app/models/moon.py @@ -14,13 +14,13 @@ def to_dict(self): moon_as_dict["name"] = self.name moon_as_dict["size"] = self.size moon_as_dict["description"] = self.description - moon_as_dict["planet_id"] = self.planet_id + #moon_as_dict["planet_id"] = self.planet_id return moon_as_dict @classmethod def from_dict(cls,moon_data): new_moon = Moon(name=moon_data["name"], size=float(moon_data["size"]), - description=moon_data["description"], - planet_id = int(moon_data["planet_id"])) + description=moon_data["description"]) + #planet_id = int(moon_data["planet_id"])) return new_moon \ No newline at end of file diff --git a/app/routes/moon_routes.py b/app/routes/moon_routes.py index 15e3e535b..b79157d40 100644 --- a/app/routes/moon_routes.py +++ b/app/routes/moon_routes.py @@ -60,4 +60,4 @@ def delete_moon(moon_id): db.session.delete(moon) db.session.commit() - return make_response(jsonify(f"Planet {moon.id} successfully deleted"), 200) \ No newline at end of file + return make_response(jsonify(f"Moon {moon.id} successfully deleted"), 200) \ No newline at end of file diff --git a/app/routes/validate_routes.py b/app/routes/validate_routes.py index 7691ba981..755cec1a0 100644 --- a/app/routes/validate_routes.py +++ b/app/routes/validate_routes.py @@ -42,7 +42,7 @@ def validate_moon_user_input(moon_value): or moon_value["name"] == "" \ or "size" not in moon_value \ or not (isinstance(moon_value["size"], float) or isinstance(moon_value["size"], int)) \ - or moon_value["size"] <0 \ + or moon_value["size"] <=0 \ or "description" not in moon_value \ or not isinstance(moon_value["description"], str) \ or moon_value["description"] == "": diff --git a/tests/conftest.py b/tests/conftest.py index 404fee80a..421d914ba 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -113,4 +113,35 @@ def three_planets_with_moons(app): moons = [moon4]) db.session.add_all([planet_mercury, planet_venus, planet_earth]) - db.session.commit() \ No newline at end of file + db.session.commit() + +@pytest.fixture +def one_moon(app): + moon1 = Moon( + name = "Test1", + description = "Fantasy moon for testing purpose.", + size = 3.5) + + db.session.add(moon1) + db.session.commit() + db.session.refresh(moon1, ["id"]) + return moon1 + +@pytest.fixture +def three_moons(app): + moon1 = Moon( + name = "Test1", + description = "Fantasy moon for testing purpose.", + size = 3.5) + + moon2 = Moon( + name = "Test2", + description = "Fantasy moon for testing purpose.", + size = 4.0) + + moon3 = Moon( + name = "Test3", + description = "Fantasy moon for testing purpose.", + size = 5.5) + db.session.add_all([moon1, moon2, moon3]) + db.session.commit() diff --git a/tests/test_moon_routes.py b/tests/test_moon_routes.py index 15e293027..bac0332d8 100644 --- a/tests/test_moon_routes.py +++ b/tests/test_moon_routes.py @@ -3,283 +3,141 @@ import pytest #### POST/ Create moon #### -def test_create_moon_valid_request_return_200(client): # return ""Moon {new_moon.name} successfully created", 201 +def test_create_moon_valid_request_return_201(client): # Act response = client.post("/moons", json = { "description": "Fantasy moon for testing purpose.", "name": "Test1", - "size": 3.6, - "planet_id": + "size": 3.6 }) response_body = response.get_json() # Assert assert response.status_code == 201 - assert response_body == "Planet Mars successfully created" + assert response_body == "Moon Test1 successfully created" -def test_create_planet_invalid_request_empty_name(client): +def test_create_moon_invalid_request_empty_name_return_400(client): # Act - response = client.post("/planets", json = { - "name": "", - "description": "This unknown planet is the imaginary planet for purpose of testing.", - "length_of_year": 10}) - response_body = response.get_json() - - # Assert - assert response.status_code == 400 - assert response_body == "Invalid request" - -def test_create_planet_invalid_request_lenght_of_year_zero(client): - # Act - response = client.post("/planets", json = { - "name": "Test", - "description": "This unknown planet is the imaginary planet for purpose of testing.", - "length_of_year": 0}) - response_body = response.get_json() - - # Assert - assert response.status_code == 400 - assert response_body == "Invalid request" - -def test_create_planet_invalid_request_lenght_of_year_negative(client): - # Act - response = client.post("/planets", json = { - 'name': 'Test', - 'description': 'This unknown planet is the imaginary planet for purpose of testing.', - 'length_of_year': -100}) + response = client.post("/moons", json = { + "description": "Fantasy moon for testing purpose.", + "size": 3.6 + }) response_body = response.get_json() # Assert assert response.status_code == 400 assert response_body == "Invalid request" -def test_create_planet_invalid_request_description_empty(client): +def test_create_moon_invalid_request_size_zero_return_400(client): # Act - response = client.post("/planets", json = { - 'name': 'Test', - 'description': '', - 'length_of_year': 10}) + response = client.post("/moons", json = { + "description": "Fantasy moon for testing purpose.", + "name": "Test1", + "size": 0 + }) response_body = response.get_json() # Assert assert response.status_code == 400 assert response_body == "Invalid request" -#### PUT #### -def test_update_planet_valid_request(client, one_planet): - # Act - planet_id = one_planet.id - response = client.put(f"/planets/{one_planet.id}", json = { - "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", - "length_of_year": 88, - "name": "Mercury_updated" - }) - response_body = response.get_json() - - # Assert - assert response.status_code == 200 - assert response_body == f"Planet {planet_id} successfully updated" - -def test_update_planet_not_exist_id(client, one_planet): +def test_create_moon_invalid_request_description_empty_return_400(client): # Act - response = client.put("/planets/9", json = { - "description": "Mars is a dusty, cold, desert world with a very thin atmosphere.", - "length_of_year": 687, - "name": "Mars" + response = client.post("/moons", json = { + "name": "Test1", + "size": 3.6 }) response_body = response.get_json() - # Assert - assert response.status_code == 404 - assert response_body == f"Planet 9 not found" - -def test_update_planet_invalid_type_id(client, one_planet): - # Act - planet_id = "hello" - response = client.put(f"/planets/{planet_id}", json = { - "description": "Mars is a dusty, cold, desert world with a very thin atmosphere.", - "length_of_year": 687, - "name": "Mars" - }) - response_body = response.get_json() - # Assert - assert response.status_code == 400 - assert response_body == f"Planet {planet_id} invalid" - -def test_update_planet_invalid_request_empty_name(client, one_planet): - # Act - response = client.put(f"/planets/{one_planet.id}", json = { - "name": "", - "description": "This unknown planet is the imaginary planet for purpose of testing.", - "length_of_year": 10}) - response_body = response.get_json() - - # Assert - assert response.status_code == 400 - assert response_body == "Invalid request" - -def test_update_planet_invalid_request_lenght_of_year_zero(client, one_planet): - # Act - response = client.put(f"/planets/{one_planet.id}", json = { - "name": "Test", - "description": "This unknown planet is the imaginary planet for purpose of testing.", - "length_of_year": 0}) - response_body = response.get_json() - # Assert assert response.status_code == 400 assert response_body == "Invalid request" -def test_update_planet_invalid_request_lenght_of_year_negative(client, one_planet): +#### DELETE/ Delete moon #### +def test_delete_moon_by_id_valid_request_return_success_message(client, one_moon): # Act - response = client.put(f"/planets/{one_planet.id}", json = { - 'name': 'Test', - 'description': 'This unknown planet is the imaginary planet for purpose of testing.', - 'length_of_year': -100}) - response_body = response.get_json() - - # Assert - assert response.status_code == 400 - assert response_body == "Invalid request" - -def test_update_planet_invalid_request_description_empty(client, one_planet): - # Act - response = client.put(f"/planets/{one_planet.id}", json = { - 'name': 'Test', - 'description': '', - 'length_of_year': 10}) - response_body = response.get_json() - - # Assert - assert response.status_code == 400 - assert response_body == "Invalid request" - -#### DELETE #### -def test_delete_planet_by_id_valid_request_with_zero_moons(client, one_planet): - # Act - planet_id = one_planet.id - response = client.delete(f"/planets/{planet_id}") + moon_id = one_moon.id + response = client.delete(f"/moons/{moon_id}") response_body = response.get_json() # Assert assert response.status_code == 200 - assert response_body == f"Planet {planet_id} successfully deleted" + assert response_body == f"Moon {moon_id} successfully deleted" -def test_delete_planet_by_id_valid_request_with_two_moons(client, one_planet_with_moons): +def test_delete_moon_by_id_invalid_id_return_400(client, one_moon): # Act - planet_id = one_planet_with_moons.id - response = client.delete(f"/planets/{planet_id}") - response_body = response.get_json() - # Assert - assert response.status_code == 200 - assert response_body == f"Planet {planet_id} successfully deleted" - # Would like to add assert to check that moons deleted too - # dont know how - # will be happy to recieve the feedback :) - -def test_delete_planet_by_id_invalid_id(client, one_planet): - # Act - planet_id = "hello" - response = client.delete(f"/planets/{planet_id}") + moon_id = "hello" + response = client.delete(f"/moons/{moon_id}") response_body = response.get_json() # Assert assert response.status_code == 400 - assert response_body == f"Planet {planet_id} invalid" + assert response_body == f"Moon {moon_id} invalid" -def test_delete_planet_by_not_existed_id(client, one_planet): - planet_id = 9 - response = client.delete(f"/planets/{planet_id}") +def test_delete_moon_by_not_existed_id_return_404(client, one_moon): + moon_id = 2 + response = client.delete(f"/moons/{moon_id}") response_body = response.get_json() # Assert assert response.status_code == 404 - assert response_body == f"Planet {planet_id} not found" - + assert response_body == f"Moon {moon_id} not found" + ####GET#### -def test_get_planet1_from_fixture_one_planet_return_200(client,one_planet): +def test_get_moon_by_id_return_200(client,one_moon): # Act - response = client.get("/planets/1") + response = client.get("/moons/1") response_body = response.get_json() # Assert assert response.status_code == 200 assert response_body == { "id":1, - "name": "Mercury", - "length_of_year": 88, - "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", - "moons": [] + "name": "Test1", + "size": 3.5, + "description": "Fantasy moon for testing purpose." } -def test_get_planet1_from_fixture_three_planet_return_200(client,three_planets): +def test_get_all_moons_return_200(client,three_moons): # Act - response = client.get("/planets/1") + response = client.get("/moons") response_body = response.get_json() # Assert assert response.status_code == 200 - assert response_body == { + assert response_body == [ + { "id":1, - "name": "Mercury", - "length_of_year": 88, - "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", - "moons": [] + "name": "Test1", + "size": 3.5, + "description": "Fantasy moon for testing purpose." + }, + { + "id":2, + "name": "Test2", + "size": 4.0, + "description": "Fantasy moon for testing purpose." + }, + { + "id":3, + "name": "Test3", + "size": 5.5, + "description": "Fantasy moon for testing purpose." } + ] -def test_get_planet1_no_fixture_return_404(client): +def test_get_moon_by_not_exist_did_return_404(client, one_moon): # Act - response = client.get("/planets/1") + response = client.get("/moons/2") response_body = response.get_json() # Assert assert response.status_code == 404 - assert response_body == "Planet 1 not found" - -def test_get_planets_in_array_return_200(client,one_planet): - # Act - response = client.get("/planets") - response_body = response.get_json() - - # Assert - assert response.status_code == 200 - assert len(response_body) == 1 - assert response_body == [ - { - "id":1, - "name": "Mercury", - "length_of_year": 88, - "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", - "moons": [] - } - ] + assert response_body == "Moon 2 not found" -def test_get_planets_in_array_with_fixture_three_planets_return_200(client,three_planets): +def test_get_moon_by_invalid_type_id_return_400(client,one_moon): # Act - response = client.get("/planets") + moon_id = "hello" + response = client.get(f"/planets/{moon_id}") response_body = response.get_json() # Assert - assert response.status_code == 200 - assert len(response_body) == 3 - assert response_body == [ - { - "id":1, - "name": "Mercury", - "length_of_year": 88, - "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", - "moons": [] - }, - { - "id":2, - "name": "Venus", - "length_of_year": 225, - "description": "Venus spins slowly in the opposite direction from most planets.", - "moons": [] - }, - { - "id":3, - "name": "Earth", - "length_of_year": 365, - "description": "Earth — our home planet.", - "moons": [] - } -] - + assert response.status_code == 400 + assert response_body == f"Planet {moon_id} invalid" diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index c6fb1b382..5cea46550 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -3,7 +3,7 @@ import pytest #### POST/ Create planet #### -def test_create_planet_valid_request(client): +def test_create_planet_valid_request_return_201(client): # Act response = client.post("/planets", json = { "description": "Mars is a dusty, cold, desert world with a very thin atmosphere.", @@ -16,7 +16,7 @@ def test_create_planet_valid_request(client): assert response.status_code == 201 assert response_body == "Planet Mars successfully created" -def test_create_planet_invalid_request_empty_name(client): +def test_create_planet_invalid_request_empty_name_return_400(client): # Act response = client.post("/planets", json = { "name": "", @@ -28,7 +28,7 @@ def test_create_planet_invalid_request_empty_name(client): assert response.status_code == 400 assert response_body == "Invalid request" -def test_create_planet_invalid_request_lenght_of_year_zero(client): +def test_create_planet_invalid_request_lenght_of_year_zero_return_400(client): # Act response = client.post("/planets", json = { "name": "Test", @@ -40,7 +40,7 @@ def test_create_planet_invalid_request_lenght_of_year_zero(client): assert response.status_code == 400 assert response_body == "Invalid request" -def test_create_planet_invalid_request_lenght_of_year_negative(client): +def test_create_planet_invalid_request_lenght_of_year_negative_return_400(client): # Act response = client.post("/planets", json = { 'name': 'Test', @@ -52,7 +52,7 @@ def test_create_planet_invalid_request_lenght_of_year_negative(client): assert response.status_code == 400 assert response_body == "Invalid request" -def test_create_planet_invalid_request_description_empty(client): +def test_create_planet_invalid_request_description_empty_return_400(client): # Act response = client.post("/planets", json = { 'name': 'Test', @@ -253,7 +253,7 @@ def test_get_all_planets_without_moons_return_planets_info(client,three_planets) assert response.status_code == 200 assert len(response_body) == 3 assert response_body == [ - { + { "id":1, "name": "Mercury", "length_of_year": 88, @@ -310,7 +310,7 @@ def test_get_all_planets_with_moons_return_planets_info(client,three_planets_wit def test_get_all_planets_with_moons_sorted_by_name_return_planets_info(client,three_planets_with_moons): # Act - data = {"sort_by_name"} + data = {"sort": "name"} # Act response = client.get("/planets", query_string = data) response_body = response.get_json() @@ -318,8 +318,15 @@ def test_get_all_planets_with_moons_sorted_by_name_return_planets_info(client,th # Assert assert response.status_code == 200 assert len(response_body) == 3 - assert response_body == [ - { + assert response_body == [ + { + "id":3, + "name": "Earth", + "length_of_year": 365, + "description": "Earth — our home planet.", + "moons": ["Moon_Test4"] + }, + { "id":1, "name": "Mercury", "length_of_year": 88, @@ -332,12 +339,5 @@ def test_get_all_planets_with_moons_sorted_by_name_return_planets_info(client,th "length_of_year": 225, "description": "Venus spins slowly in the opposite direction from most planets.", "moons": ["Moon_Test3"] - }, - { - "id":3, - "name": "Earth", - "length_of_year": 365, - "description": "Earth — our home planet.", - "moons": ["Moon_Test4"] } ] \ No newline at end of file From 5808f9da3b72d15b225903a464de8d0633b09743 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Sat, 7 Jan 2023 22:44:53 -0800 Subject: [PATCH 81/85] Added test_moons_inside_planet_routes.py --- app/routes/planet_routes.py | 16 +- tests/test_moons_inside_planet_routes.py | 144 ++++++++++++++++++ tests/test_planet_routes.py | 34 +++++ ...test_models.py => test_validate_routes.py} | 0 4 files changed, 184 insertions(+), 10 deletions(-) create mode 100644 tests/test_moons_inside_planet_routes.py rename tests/{test_models.py => test_validate_routes.py} (100%) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 83785132f..2ac528aec 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -19,24 +19,20 @@ def create_planet(): # Get all planets info # Return JSON list @planets_bp.route("", methods = ["GET"]) -def get_planets_query(): +def get_all_planets_query(): planet_query = Planet.query + # Filtering by name (return all records which name contains planet_name_query) planet_name_query = request.args.get("name") if planet_name_query: planet_query = planet_query.filter(Planet.name.ilike(f"%{planet_name_query}%")) - sort_by_name_query = request.args.get("sort_by_name") - if sort_by_name_query == "desc": - planet_query = planet_query.order_by(Planet.name.desc()).all() - elif sort_by_name_query == "asc": + # Sort + sort_query = request.args.get("sort") + if sort_query == "name": planet_query = planet_query.order_by(Planet.name).all() - - sort_by_length_of_year_query = request.args.get("sort_by_length_of_year") - if sort_by_length_of_year_query == "desc": - planet_query = planet_query.order_by(Planet.length_of_year.desc()).all() - elif sort_by_length_of_year_query == "asc": + if sort_query == "length_of_year": planet_query = planet_query.order_by(Planet.length_of_year).all() planet_response = [] diff --git a/tests/test_moons_inside_planet_routes.py b/tests/test_moons_inside_planet_routes.py new file mode 100644 index 000000000..15ca7bfb6 --- /dev/null +++ b/tests/test_moons_inside_planet_routes.py @@ -0,0 +1,144 @@ +from werkzeug.exceptions import HTTPException +from app.models.moon import Moon +from app.models.planet import Planet +import pytest + +#### POST/ Create moon #### +def test_create_moon_valid_request_return_201(client): + # Act + response = client.post("/moons", json = { + "description": "Fantasy moon for testing purpose.", + "name": "Test1", + "size": 3.6 + }) + response_body = response.get_json() + + # Assert + assert response.status_code == 201 + assert response_body == "Moon Test1 successfully created" + +def test_create_moon_invalid_request_empty_name_return_400(client): + # Act + response = client.post("/moons", json = { + "description": "Fantasy moon for testing purpose.", + "size": 3.6 + }) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +def test_create_moon_invalid_request_size_zero_return_400(client): + # Act + response = client.post("/moons", json = { + "description": "Fantasy moon for testing purpose.", + "name": "Test1", + "size": 0 + }) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +def test_create_moon_invalid_request_description_empty_return_400(client): + # Act + response = client.post("/moons", json = { + "name": "Test1", + "size": 3.6 + }) + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == "Invalid request" + +#### DELETE/ Delete moon #### +def test_delete_moon_by_id_valid_request_return_success_message(client, one_moon): + # Act + moon_id = one_moon.id + response = client.delete(f"/moons/{moon_id}") + response_body = response.get_json() + # Assert + assert response.status_code == 200 + assert response_body == f"Moon {moon_id} successfully deleted" + +def test_delete_moon_by_id_invalid_id_return_400(client, one_moon): + # Act + moon_id = "hello" + response = client.delete(f"/moons/{moon_id}") + response_body = response.get_json() + # Assert + assert response.status_code == 400 + assert response_body == f"Moon {moon_id} invalid" + +def test_delete_moon_by_not_existed_id_return_404(client, one_moon): + moon_id = 2 + response = client.delete(f"/moons/{moon_id}") + response_body = response.get_json() + # Assert + assert response.status_code == 404 + assert response_body == f"Moon {moon_id} not found" + +####GET#### +def test_get_moon_by_id_return_200(client,one_moon): + # Act + response = client.get("/moons/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == { + "id":1, + "name": "Test1", + "size": 3.5, + "description": "Fantasy moon for testing purpose." + } + +def test_get_all_moons_return_200(client,three_moons): + # Act + response = client.get("/moons") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == [ + { + "id":1, + "name": "Test1", + "size": 3.5, + "description": "Fantasy moon for testing purpose." + }, + { + "id":2, + "name": "Test2", + "size": 4.0, + "description": "Fantasy moon for testing purpose." + }, + { + "id":3, + "name": "Test3", + "size": 5.5, + "description": "Fantasy moon for testing purpose." + } + ] + +def test_get_moon_by_not_exist_did_return_404(client, one_moon): + # Act + response = client.get("/moons/2") + response_body = response.get_json() + + # Assert + assert response.status_code == 404 + assert response_body == "Moon 2 not found" + +def test_get_moon_by_invalid_type_id_return_400(client,one_moon): + # Act + moon_id = "hello" + response = client.get(f"/planets/{moon_id}") + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == f"Planet {moon_id} invalid" diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index 5cea46550..60889bc06 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -340,4 +340,38 @@ def test_get_all_planets_with_moons_sorted_by_name_return_planets_info(client,th "description": "Venus spins slowly in the opposite direction from most planets.", "moons": ["Moon_Test3"] } +] + +def test_get_all_planets_with_moons_sorted_by_length_of_year_return_planets_info(client,three_planets_with_moons): + # Act + data = {"sort": "length_of_year"} + # Act + response = client.get("/planets", query_string = data) + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert len(response_body) == 3 + assert response_body == [ + { + "id":1, + "name": "Mercury", + "length_of_year": 88, + "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", + "moons": ["Moon_Test1", "Moon_Test2"] + }, + { + "id":2, + "name": "Venus", + "length_of_year": 225, + "description": "Venus spins slowly in the opposite direction from most planets.", + "moons": ["Moon_Test3"] + }, + { + "id":3, + "name": "Earth", + "length_of_year": 365, + "description": "Earth — our home planet.", + "moons": ["Moon_Test4"] + }, ] \ No newline at end of file diff --git a/tests/test_models.py b/tests/test_validate_routes.py similarity index 100% rename from tests/test_models.py rename to tests/test_validate_routes.py From 916cd9bf51071d64a52d33d81337d76aff3012f0 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Sun, 8 Jan 2023 00:55:23 -0800 Subject: [PATCH 82/85] added tests for create moon of planet with planet id --- app/routes/planet_routes.py | 7 ++-- app/routes/validate_routes.py | 2 +- tests/conftest.py | 7 ++-- tests/test_moons_inside_planet_routes.py | 41 +++++++++++++++--------- 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 2ac528aec..68aad2d26 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -84,11 +84,10 @@ def delete_planet(planet_id): @planets_bp.route("//moons", methods=["POST"]) def add_new_moon_to_planet(planet_id): planet = validate_model(Planet, planet_id) + moon_value = validate_moon_user_input(request.get_json()) + moon = Moon.from_dict(moon_value) - request_body = request.get_json() - moon = Moon.from_dict(request_body) - #moon.planet = planet - moon.planet_id = planet_id + moon.planet_id = planet.id db.session.add(moon) db.session.commit() diff --git a/app/routes/validate_routes.py b/app/routes/validate_routes.py index 755cec1a0..96886e7cf 100644 --- a/app/routes/validate_routes.py +++ b/app/routes/validate_routes.py @@ -35,7 +35,7 @@ def validate_planet_user_input(planet_value): # Returning the valid JSON if valid input def validate_moon_user_input(moon_value): - if not "planet_id": moon_value["planet_id"] = 0 #### + #if not "planet_id": moon_value["planet_id"] = 0 #### if "name" not in moon_value \ or not isinstance(moon_value["name"], str) \ diff --git a/tests/conftest.py b/tests/conftest.py index 421d914ba..b84676149 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -39,10 +39,9 @@ def one_planet(app): @pytest.fixture def one_planet_with_moons(app): moon1 = Moon( - description = "Moon for testing purpose.", - size = 173.1, - name = "Moon_Test1" - ) + name = "Test1", + description = "Fantasy moon for testing purpose.", + size = 3.5) moon2 = Moon( description = "Moon just for testing.", size = 17, diff --git a/tests/test_moons_inside_planet_routes.py b/tests/test_moons_inside_planet_routes.py index 15ca7bfb6..38d627e0e 100644 --- a/tests/test_moons_inside_planet_routes.py +++ b/tests/test_moons_inside_planet_routes.py @@ -3,10 +3,12 @@ from app.models.planet import Planet import pytest -#### POST/ Create moon #### -def test_create_moon_valid_request_return_201(client): +#### POST/ Create moon for planet #### +def test_create_moon_for_planet_id_valid_request_return_201(client, one_planet): + # Arange + planet_id = one_planet.id # Act - response = client.post("/moons", json = { + response = client.post(f"/planets/{planet_id}/moons", json = { "description": "Fantasy moon for testing purpose.", "name": "Test1", "size": 3.6 @@ -15,13 +17,16 @@ def test_create_moon_valid_request_return_201(client): # Assert assert response.status_code == 201 - assert response_body == "Moon Test1 successfully created" + assert response_body == f"Moon Test1 added to the planet {one_planet.name}." -def test_create_moon_invalid_request_empty_name_return_400(client): +def test_create_moon_for_planet_invalid_request_empty_name_return_400(client, one_planet): + # Arange + planet_id = one_planet.id # Act - response = client.post("/moons", json = { + response = client.post(f"/planets/{planet_id}/moons", json = { "description": "Fantasy moon for testing purpose.", - "size": 3.6 + "size": 3.6, + "planet_id": planet_id }) response_body = response.get_json() @@ -29,9 +34,11 @@ def test_create_moon_invalid_request_empty_name_return_400(client): assert response.status_code == 400 assert response_body == "Invalid request" -def test_create_moon_invalid_request_size_zero_return_400(client): +def test_create_moon_for_planet_invalid_request_size_zero_return_400(client, one_planet): + # Arange + planet_id = one_planet.id # Act - response = client.post("/moons", json = { + response = client.post(f"/planets/{planet_id}/moons", json = { "description": "Fantasy moon for testing purpose.", "name": "Test1", "size": 0 @@ -42,9 +49,11 @@ def test_create_moon_invalid_request_size_zero_return_400(client): assert response.status_code == 400 assert response_body == "Invalid request" -def test_create_moon_invalid_request_description_empty_return_400(client): +def test_create_moon_for_planet_invalid_request_description_empty_return_400(client, one_planet): + # Arange + planet_id = one_planet.id # Act - response = client.post("/moons", json = { + response = client.post(f"/planets/{planet_id}/moons", json = { "name": "Test1", "size": 3.6 }) @@ -54,11 +63,13 @@ def test_create_moon_invalid_request_description_empty_return_400(client): assert response.status_code == 400 assert response_body == "Invalid request" -#### DELETE/ Delete moon #### -def test_delete_moon_by_id_valid_request_return_success_message(client, one_moon): +#### DELETE/ Delete moon for planet #### +def test_delete_moon_for_planet_by_id_valid_request_return_success_message(client, one_planet_with_moons): + # Arange + planet_id = 1 + moon_id = 1 # Act - moon_id = one_moon.id - response = client.delete(f"/moons/{moon_id}") + response = client.delete(f"/{planet_id}/moons/{moon_id}") response_body = response.get_json() # Assert assert response.status_code == 200 From a484a823a3f5530f25979acd4d8fb328018e216d Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Sun, 8 Jan 2023 01:27:41 -0800 Subject: [PATCH 83/85] Complete tests --- tests/test_moon_routes.py | 4 +- tests/test_moons_inside_planet_routes.py | 81 ++++++++---------------- tests/test_planet_routes.py | 2 +- 3 files changed, 29 insertions(+), 58 deletions(-) diff --git a/tests/test_moon_routes.py b/tests/test_moon_routes.py index bac0332d8..4fe48bba1 100644 --- a/tests/test_moon_routes.py +++ b/tests/test_moon_routes.py @@ -135,9 +135,9 @@ def test_get_moon_by_not_exist_did_return_404(client, one_moon): def test_get_moon_by_invalid_type_id_return_400(client,one_moon): # Act moon_id = "hello" - response = client.get(f"/planets/{moon_id}") + response = client.get(f"/moons/{moon_id}") response_body = response.get_json() # Assert assert response.status_code == 400 - assert response_body == f"Planet {moon_id} invalid" + assert response_body == f"Moon {moon_id} invalid" diff --git a/tests/test_moons_inside_planet_routes.py b/tests/test_moons_inside_planet_routes.py index 38d627e0e..12e724d92 100644 --- a/tests/test_moons_inside_planet_routes.py +++ b/tests/test_moons_inside_planet_routes.py @@ -63,93 +63,64 @@ def test_create_moon_for_planet_invalid_request_description_empty_return_400(cli assert response.status_code == 400 assert response_body == "Invalid request" -#### DELETE/ Delete moon for planet #### -def test_delete_moon_for_planet_by_id_valid_request_return_success_message(client, one_planet_with_moons): +####GET moon inside of planet route#### +def test_get_moon_for_planet_by_id_for_planet_id_return_200(client,three_planets_with_moons): # Arange planet_id = 1 moon_id = 1 # Act - response = client.delete(f"/{planet_id}/moons/{moon_id}") + response = client.get(f"planets/{planet_id}/moons/{moon_id}") response_body = response.get_json() - # Assert - assert response.status_code == 200 - assert response_body == f"Moon {moon_id} successfully deleted" - -def test_delete_moon_by_id_invalid_id_return_400(client, one_moon): - # Act - moon_id = "hello" - response = client.delete(f"/moons/{moon_id}") - response_body = response.get_json() - # Assert - assert response.status_code == 400 - assert response_body == f"Moon {moon_id} invalid" - -def test_delete_moon_by_not_existed_id_return_404(client, one_moon): - moon_id = 2 - response = client.delete(f"/moons/{moon_id}") - response_body = response.get_json() - # Assert - assert response.status_code == 404 - assert response_body == f"Moon {moon_id} not found" - -####GET#### -def test_get_moon_by_id_return_200(client,one_moon): - # Act - response = client.get("/moons/1") - response_body = response.get_json() - # Assert assert response.status_code == 200 assert response_body == { "id":1, - "name": "Test1", - "size": 3.5, - "description": "Fantasy moon for testing purpose." + "name": "Moon_Test1", + "size": 173.1, + "description": "Moon1 for testing purpose." } -def test_get_all_moons_return_200(client,three_moons): +def test_get_all_moons_for_planet_valid_planet_id_return_200_info_moons(client,three_planets_with_moons): + # Arange + planet_id = 1 # Act - response = client.get("/moons") + response = client.get(f"planets/{planet_id}/moons") response_body = response.get_json() - # Assert assert response.status_code == 200 assert response_body == [ { "id":1, - "name": "Test1", - "size": 3.5, - "description": "Fantasy moon for testing purpose." + "name": "Moon_Test1", + "size": 173.1, + "description": "Moon1 for testing purpose." }, { "id":2, - "name": "Test2", - "size": 4.0, - "description": "Fantasy moon for testing purpose." - }, - { - "id":3, - "name": "Test3", - "size": 5.5, - "description": "Fantasy moon for testing purpose." + "name": "Moon_Test2", + "size": 17.0, + "description": "Moon2 just for testing." } ] -def test_get_moon_by_not_exist_did_return_404(client, one_moon): +def test_get_all_moons_for_planet_by_not_exist_id_return_404(client, three_planets_with_moons): + # Arange + planet_id = 4 # Act - response = client.get("/moons/2") + response = client.get(f"planets/{planet_id}/moons") response_body = response.get_json() # Assert assert response.status_code == 404 - assert response_body == "Moon 2 not found" + assert response_body == f"Planet {planet_id} not found" -def test_get_moon_by_invalid_type_id_return_400(client,one_moon): +def test_get_all_moons_for_planet_by_invalid_type_id_return_400(client, three_planets_with_moons): + # Arange + planet_id = "hello" # Act - moon_id = "hello" - response = client.get(f"/planets/{moon_id}") + response = client.get(f"planets/{planet_id}/moons") response_body = response.get_json() # Assert assert response.status_code == 400 - assert response_body == f"Planet {moon_id} invalid" + assert response_body == f"Planet {planet_id} invalid" diff --git a/tests/test_planet_routes.py b/tests/test_planet_routes.py index 60889bc06..1e4fc7237 100644 --- a/tests/test_planet_routes.py +++ b/tests/test_planet_routes.py @@ -240,7 +240,7 @@ def test_get_planet_with_moon_valid_id_return_planet_info(client,one_planet_with "name": "Mercury", "length_of_year": 88, "description": "Mercury is the smallest planet in the Solar System and the closest to the Sun.", - "moons": ["Moon_Test1", "Moon_Test2"] + "moons": ["Test1", "Moon_Test2"] } #### GET/ Read all planets #### From d7d7a2636de0b1dd9f341514c9c9e52ef40ee41c Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Sun, 8 Jan 2023 01:48:53 -0800 Subject: [PATCH 84/85] Added comments, cleanup code --- app/models/moon.py | 2 -- app/routes/moon_routes.py | 6 ++++ app/routes/planet_routes.py | 6 +++- app/routes/validate_routes.py | 12 +++++-- tests/conftest.py | 17 ++++++--- tests/test_moon_routes.py | 45 ++++++++++-------------- tests/test_moons_inside_planet_routes.py | 2 ++ tests/test_validate_routes.py | 1 - 8 files changed, 54 insertions(+), 37 deletions(-) diff --git a/app/models/moon.py b/app/models/moon.py index c26b1b235..1a610a61f 100644 --- a/app/models/moon.py +++ b/app/models/moon.py @@ -14,7 +14,6 @@ def to_dict(self): moon_as_dict["name"] = self.name moon_as_dict["size"] = self.size moon_as_dict["description"] = self.description - #moon_as_dict["planet_id"] = self.planet_id return moon_as_dict @classmethod @@ -22,5 +21,4 @@ def from_dict(cls,moon_data): new_moon = Moon(name=moon_data["name"], size=float(moon_data["size"]), description=moon_data["description"]) - #planet_id = int(moon_data["planet_id"])) return new_moon \ No newline at end of file diff --git a/app/routes/moon_routes.py b/app/routes/moon_routes.py index b79157d40..530ec2ab6 100644 --- a/app/routes/moon_routes.py +++ b/app/routes/moon_routes.py @@ -14,10 +14,13 @@ def get_all_moons_query(): moon_query = Moon.query # Filtering by moon name (return all records which name contains planet_name_query) moon_name_query = request.args.get("name") + if moon_name_query: moon_query = moon_query.filter(Moon.name.ilike(f"%{moon_name_query}%")) + # Sorting by moon name sort_by_name_query = request.args.get("sort_by_name") + if sort_by_name_query == "desc": moon_query = moon_query.order_by(Moon.name.desc()).all() elif sort_by_name_query == "asc": @@ -25,11 +28,13 @@ def get_all_moons_query(): # Sorting by moon size moon_sort_size_query = request.args.get("sort_by_size") + if moon_sort_size_query == "desc": moon_query = moon_query.order_by(Moon.size.desc()).all() elif sort_by_name_query == "asc": moon_query = moon_query.order_by(Moon.size).all() + # Build response moon_response = [] for moon in moon_query: moon_response.append(moon.to_dict()) @@ -57,6 +62,7 @@ def create_moon(): @moons_bp.route("/",methods=["DELETE"]) def delete_moon(moon_id): moon = validate_model(Moon, moon_id) + db.session.delete(moon) db.session.commit() diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py index 68aad2d26..b3ab7e580 100644 --- a/app/routes/planet_routes.py +++ b/app/routes/planet_routes.py @@ -14,6 +14,7 @@ def create_planet(): db.session.add(new_planet) db.session.commit() + return make_response(jsonify(f"Planet {new_planet.name} successfully created"), 201) # Get all planets info @@ -30,8 +31,10 @@ def get_all_planets_query(): # Sort sort_query = request.args.get("sort") + if sort_query == "name": planet_query = planet_query.order_by(Planet.name).all() + if sort_query == "length_of_year": planet_query = planet_query.order_by(Planet.length_of_year).all() @@ -66,6 +69,7 @@ def update_planet(planet_id): @planets_bp.route("/",methods=["DELETE"]) def delete_planet(planet_id): planet = validate_model(Planet, planet_id) + if len(planet.moons)>0: i = 0 while i < len(planet.moons): @@ -85,8 +89,8 @@ def delete_planet(planet_id): def add_new_moon_to_planet(planet_id): planet = validate_model(Planet, planet_id) moon_value = validate_moon_user_input(request.get_json()) + moon = Moon.from_dict(moon_value) - moon.planet_id = planet.id db.session.add(moon) diff --git a/app/routes/validate_routes.py b/app/routes/validate_routes.py index 96886e7cf..3319ea67a 100644 --- a/app/routes/validate_routes.py +++ b/app/routes/validate_routes.py @@ -11,14 +11,18 @@ def validate_model(cls, model_id): model_id = int(model_id) except: abort(make_response(jsonify(f"{cls.__name__} {model_id} invalid"), 400)) + class_obj = cls.query.get(model_id) + if not class_obj: abort(make_response(jsonify(f"{cls.__name__} {model_id} not found"), 404)) + return class_obj # Validating the user input to create or update the table planet # Returning the valid JSON if valid input def validate_planet_user_input(planet_value): + if "name" not in planet_value \ or not isinstance(planet_value["name"], str) \ or planet_value["name"] == "" \ @@ -28,14 +32,14 @@ def validate_planet_user_input(planet_value): or "description" not in planet_value \ or not isinstance(planet_value["description"], str) \ or planet_value["description"] == "": - return abort(make_response(jsonify("Invalid request"), 400)) + + return abort(make_response(jsonify("Invalid request"), 400)) + return planet_value # Validating the user input to create or update the table moon # Returning the valid JSON if valid input def validate_moon_user_input(moon_value): - - #if not "planet_id": moon_value["planet_id"] = 0 #### if "name" not in moon_value \ or not isinstance(moon_value["name"], str) \ @@ -46,5 +50,7 @@ def validate_moon_user_input(moon_value): or "description" not in moon_value \ or not isinstance(moon_value["description"], str) \ or moon_value["description"] == "": + return abort(make_response(jsonify("Invalid request"), 400)) + return moon_value \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index b84676149..aa0dd68d5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -26,6 +26,7 @@ def client(app): @pytest.fixture def one_planet(app): + planet = Planet( name = "Mercury", description = "Mercury is the smallest planet in the Solar System and the closest to the Sun.", @@ -34,19 +35,21 @@ def one_planet(app): db.session.add(planet) db.session.commit() db.session.refresh(planet, ["id"]) + return planet @pytest.fixture def one_planet_with_moons(app): + # Moons moon1 = Moon( name = "Test1", description = "Fantasy moon for testing purpose.", size = 3.5) moon2 = Moon( description = "Moon just for testing.", - size = 17, - name = "Moon_Test2" - ) + size = 17.0, + name = "Moon_Test2") + # Planet planet_mercury = Planet( name = "Mercury", description = "Mercury is the smallest planet in the Solar System and the closest to the Sun.", @@ -56,6 +59,7 @@ def one_planet_with_moons(app): db.session.add(planet_mercury) db.session.commit() db.session.refresh(planet_mercury, ["id"]) + return planet_mercury @pytest.fixture @@ -78,6 +82,7 @@ def three_planets(app): @pytest.fixture def three_planets_with_moons(app): + # Moons moon1 = Moon( description = "Moon1 for testing purpose.", size = 173.1, @@ -94,7 +99,7 @@ def three_planets_with_moons(app): description = "Moon4 just for testing.", size = 19, name = "Moon_Test4") - + # Planets planet_mercury = Planet( name = "Mercury", description = "Mercury is the smallest planet in the Solar System and the closest to the Sun.", @@ -116,6 +121,7 @@ def three_planets_with_moons(app): @pytest.fixture def one_moon(app): + moon1 = Moon( name = "Test1", description = "Fantasy moon for testing purpose.", @@ -124,10 +130,12 @@ def one_moon(app): db.session.add(moon1) db.session.commit() db.session.refresh(moon1, ["id"]) + return moon1 @pytest.fixture def three_moons(app): + moon1 = Moon( name = "Test1", description = "Fantasy moon for testing purpose.", @@ -142,5 +150,6 @@ def three_moons(app): name = "Test3", description = "Fantasy moon for testing purpose.", size = 5.5) + db.session.add_all([moon1, moon2, moon3]) db.session.commit() diff --git a/tests/test_moon_routes.py b/tests/test_moon_routes.py index 4fe48bba1..51daa3535 100644 --- a/tests/test_moon_routes.py +++ b/tests/test_moon_routes.py @@ -11,7 +11,6 @@ def test_create_moon_valid_request_return_201(client): "size": 3.6 }) response_body = response.get_json() - # Assert assert response.status_code == 201 assert response_body == "Moon Test1 successfully created" @@ -23,7 +22,6 @@ def test_create_moon_invalid_request_empty_name_return_400(client): "size": 3.6 }) response_body = response.get_json() - # Assert assert response.status_code == 400 assert response_body == "Invalid request" @@ -36,7 +34,6 @@ def test_create_moon_invalid_request_size_zero_return_400(client): "size": 0 }) response_body = response.get_json() - # Assert assert response.status_code == 400 assert response_body == "Invalid request" @@ -48,7 +45,6 @@ def test_create_moon_invalid_request_description_empty_return_400(client): "size": 3.6 }) response_body = response.get_json() - # Assert assert response.status_code == 400 assert response_body == "Invalid request" @@ -80,12 +76,11 @@ def test_delete_moon_by_not_existed_id_return_404(client, one_moon): assert response.status_code == 404 assert response_body == f"Moon {moon_id} not found" -####GET#### +####GET/ Read moon by id#### def test_get_moon_by_id_return_200(client,one_moon): # Act response = client.get("/moons/1") response_body = response.get_json() - # Assert assert response.status_code == 200 assert response_body == { @@ -95,11 +90,28 @@ def test_get_moon_by_id_return_200(client,one_moon): "description": "Fantasy moon for testing purpose." } +def test_get_moon_by_not_exist_did_return_404(client, one_moon): + # Act + response = client.get("/moons/2") + response_body = response.get_json() + # Assert + assert response.status_code == 404 + assert response_body == "Moon 2 not found" + +def test_get_moon_by_invalid_type_id_return_400(client,one_moon): + # Act + moon_id = "hello" + response = client.get(f"/moons/{moon_id}") + response_body = response.get_json() + # Assert + assert response.status_code == 400 + assert response_body == f"Moon {moon_id} invalid" + +####GET/ Read all moons #### def test_get_all_moons_return_200(client,three_moons): # Act response = client.get("/moons") response_body = response.get_json() - # Assert assert response.status_code == 200 assert response_body == [ @@ -122,22 +134,3 @@ def test_get_all_moons_return_200(client,three_moons): "description": "Fantasy moon for testing purpose." } ] - -def test_get_moon_by_not_exist_did_return_404(client, one_moon): - # Act - response = client.get("/moons/2") - response_body = response.get_json() - - # Assert - assert response.status_code == 404 - assert response_body == "Moon 2 not found" - -def test_get_moon_by_invalid_type_id_return_400(client,one_moon): - # Act - moon_id = "hello" - response = client.get(f"/moons/{moon_id}") - response_body = response.get_json() - - # Assert - assert response.status_code == 400 - assert response_body == f"Moon {moon_id} invalid" diff --git a/tests/test_moons_inside_planet_routes.py b/tests/test_moons_inside_planet_routes.py index 12e724d92..fe1fdc880 100644 --- a/tests/test_moons_inside_planet_routes.py +++ b/tests/test_moons_inside_planet_routes.py @@ -124,3 +124,5 @@ def test_get_all_moons_for_planet_by_invalid_type_id_return_400(client, three_pl # Assert assert response.status_code == 400 assert response_body == f"Planet {planet_id} invalid" + +#### For future can add tests for delete/ update moon_of the planet, add_moon_to_planet_with_moons, etc. \ No newline at end of file diff --git a/tests/test_validate_routes.py b/tests/test_validate_routes.py index 1656dea4c..ae9252703 100644 --- a/tests/test_validate_routes.py +++ b/tests/test_validate_routes.py @@ -18,7 +18,6 @@ def test_to_dict_no_missing_data(): moons = [moon1], description="Imaginary for testing", length_of_year = 100) - # Act result = test_data.to_dict() # Assert From 6c4375eb4742da73b359d5ff7f64a0521a246e84 Mon Sep 17 00:00:00 2001 From: Catherine Bandarchuk Date: Sun, 8 Jan 2023 14:51:20 -0800 Subject: [PATCH 85/85] create procfile, added gunicorn to requirements.txt --- Procfile | 1 + requirements.txt | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 Procfile diff --git a/Procfile b/Procfile new file mode 100644 index 000000000..62e430aca --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: gunicorn 'app:create_app()' \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index fba2b3e38..b9ada8e61 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,18 +1,26 @@ alembic==1.5.4 +attrs==22.1.0 autopep8==1.5.5 blinker==1.4 certifi==2020.12.5 chardet==4.0.0 -click==7.1.2 -Flask==1.1.2 -Flask-Migrate==2.6.0 -Flask-SQLAlchemy==2.4.4 +click==8.1.3 +coverage==6.5.0 +Flask==2.2.2 +Flask-Migrate==4.0.1 +Flask-SQLAlchemy==3.0.2 +greenlet==2.0.1 +gunicorn==20.1.0 idna==2.10 -itsdangerous==1.1.0 -Jinja2==2.11.3 +iniconfig==1.1.1 +itsdangerous==2.1.2 +Jinja2==3.1.2 Mako==1.1.4 -MarkupSafe==1.1.1 +MarkupSafe==2.1.1 +packaging==22.0 +pluggy==1.0.0 psycopg2-binary==2.9.4 +py==1.11.0 pycodestyle==2.6.0 pytest==7.1.1 pytest-cov==2.12.1 @@ -21,7 +29,8 @@ python-dotenv==0.15.0 python-editor==1.0.4 requests==2.25.1 six==1.15.0 -SQLAlchemy==1.3.23 +SQLAlchemy==1.4.46 toml==0.10.2 +tomli==2.0.1 urllib3==1.26.4 -Werkzeug==1.0.1 +Werkzeug==2.2.2