From f6694f8f673769f02876f8e6254596eb2d651b7b Mon Sep 17 00:00:00 2001 From: Barbara Date: Fri, 21 Apr 2023 15:08:55 -0400 Subject: [PATCH 01/14] Wave_01 - complete --- app/__init__.py | 3 +++ app/routes.py | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/app/__init__.py b/app/__init__.py index 70b4cabfe..1123a559e 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -4,4 +4,7 @@ def create_app(test_config=None): app = Flask(__name__) + from .routes import bp + app.register_blueprint(bp) + return app diff --git a/app/routes.py b/app/routes.py index 8e9dfe684..f37731f13 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,2 +1,35 @@ -from flask import Blueprint +from flask import Blueprint, jsonify +class Planet: + def __init__(self, id, name, description, position): + self.id = id + self.name = name + self.description = description + self.position = position + +planets = [ + Planet(1, "Mercury", "Closest to the sun and smallest", "#1") + Planet(2, "Venus", "The hottest planet of the Solar System", "#2") + Planet(3, "Earth", "Seventy percent of its surface is cover with water", "#3") + Planet(4, "Mars", "Known as Red Planet because of iron oxide on its surface", "#4") + Planet(5, "Jupiter", "The largest of the solar system, it's 2.5 times larger than all the other planets combined", "#5") + Planet(6, "Saturn", "Known as a gas giant with seven ring systems surrounding it", "#6") + Planet(7 "Uranus", "It is the coldest planet of the Solar System with temperatures at around -224 degrees Celsius", "#7") + Planet(8 "Neptune", "Has the fasted wind speeds of any planet, reaching speeds of 2.160 km / 1.314 mi per hour", "#8") + ] + +bp = Blueprint("planets", __name__, url_prefix="/planets") + +@bp.route("", methods=["GET"]) +def handle_planets(): + planets_response = [] + for planet in planets: + planets_response.append( + { + "id": planet.id, + "name": planet.name, + "description": planet.description, + "position": planet.position + } + ) + return jsonify(planets_response) From 016b5a5bd7eebd5c85352c9315b395f3c880e298 Mon Sep 17 00:00:00 2001 From: Barbara Date: Fri, 21 Apr 2023 15:59:55 -0400 Subject: [PATCH 02/14] Wave_01 - changes --- app/routes.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/routes.py b/app/routes.py index f37731f13..4dd1500fd 100644 --- a/app/routes.py +++ b/app/routes.py @@ -8,14 +8,14 @@ def __init__(self, id, name, description, position): self.position = position planets = [ - Planet(1, "Mercury", "Closest to the sun and smallest", "#1") - Planet(2, "Venus", "The hottest planet of the Solar System", "#2") - Planet(3, "Earth", "Seventy percent of its surface is cover with water", "#3") - Planet(4, "Mars", "Known as Red Planet because of iron oxide on its surface", "#4") - Planet(5, "Jupiter", "The largest of the solar system, it's 2.5 times larger than all the other planets combined", "#5") - Planet(6, "Saturn", "Known as a gas giant with seven ring systems surrounding it", "#6") - Planet(7 "Uranus", "It is the coldest planet of the Solar System with temperatures at around -224 degrees Celsius", "#7") - Planet(8 "Neptune", "Has the fasted wind speeds of any planet, reaching speeds of 2.160 km / 1.314 mi per hour", "#8") + Planet(1, "Mercury", "Closest to the sun and smallest", "#1"), + Planet(2, "Venus", "The hottest planet of the Solar System", "#2"), + Planet(3, "Earth", "Seventy percent of its surface is cover with water", "#3"), + Planet(4, "Mars", "Known as Red Planet because of iron oxide on its surface", "#4"), + Planet(5, "Jupiter", "The largest of the solar system, it's 2.5 times larger than all the other planets combined", "#5"), + Planet(6, "Saturn", "Known as a gas giant with seven ring systems surrounding it", "#6"), + Planet(7, "Uranus", "It is the coldest planet of the Solar System with temperatures at around -224 degrees Celsius", "#7"), + Planet(8, "Neptune", "Has the fasted wind speeds of any planet, reaching speeds of 2.160 km / 1.314 mi per hour", "#8") ] bp = Blueprint("planets", __name__, url_prefix="/planets") From 6cebdbb4450c3d7e662eaed674d08211b5ea79ae Mon Sep 17 00:00:00 2001 From: Erina Perez Date: Mon, 24 Apr 2023 11:59:21 -0700 Subject: [PATCH 03/14] Completed wave_02 --- app/routes.py | 25 ++++++++++++++++++++++++- project-directions/wave_02.md | 1 + 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/routes.py b/app/routes.py index 4dd1500fd..1e864250f 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,4 +1,4 @@ -from flask import Blueprint, jsonify +from flask import Blueprint, jsonify, abort, make_response class Planet: def __init__(self, id, name, description, position): @@ -33,3 +33,26 @@ def handle_planets(): } ) return jsonify(planets_response) + +def validate_planet(planet_id): + try: + planet_id = int(planet_id) + except: + abort(make_response({"message":f"Planet {planet_id} invalid"}, 400)) + + for planet in planets: + if planet.id == planet_id: + return planet + + abort(make_response({"message":f"Planet {planet_id} not found"}, 404)) + +@bp.route("/", methods=["GET"]) +def handle_planet(planet_id): + planet = validate_planet(planet_id) + + return { + "id": planet.id, + "name": planet.name, + "description": planet.description, + "position": planet.position + } diff --git a/project-directions/wave_02.md b/project-directions/wave_02.md index 7ae9ac268..1cf000528 100644 --- a/project-directions/wave_02.md +++ b/project-directions/wave_02.md @@ -9,3 +9,4 @@ As a client, I want to send a request... 1. ... such that trying to get one non-existing `planet` responds with get a `404` response, so that I know the `planet` resource was not found. 1. ... such that trying to get one `planet` with an invalid `planet_id` responds with get a `400` response, so that I know the `planet_id` was invalid. + From bbc27020e867a9c4d2cee67a6007cd8af3d29eca Mon Sep 17 00:00:00 2001 From: Barbara Date: Fri, 28 Apr 2023 14:46:12 -0400 Subject: [PATCH 04/14] Completed Wave_03 - Database Setup --- app/__init__.py | 17 ++- app/models/__init__.py | 0 app/models/planet.py | 9 ++ app/routes.py | 104 +++++++++--------- migrations/README | 1 + migrations/alembic.ini | 45 ++++++++ migrations/env.py | 96 ++++++++++++++++ migrations/script.py.mako | 24 ++++ .../94b66ffc60e6_adds_planet_model.py | 38 +++++++ 9 files changed, 282 insertions(+), 52 deletions(-) create mode 100644 app/models/__init__.py create mode 100644 app/models/planet.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/94b66ffc60e6_adds_planet_model.py diff --git a/app/__init__.py b/app/__init__.py index 1123a559e..a286c810e 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,10 +1,25 @@ 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' + + # Import models here + from app.models.planet import Planet + + db.init_app(app) + migrate.init_app(app, db) + + # Register Blueprints from .routes import bp app.register_blueprint(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..abdf3a975 --- /dev/null +++ b/app/models/planet.py @@ -0,0 +1,9 @@ +from app import db + +class Planet(db.Model): + id = db.Column(db.Integer, primary_key=True, autoincrement=True) + name = db.Column(db.String) + description = db.Column(db.String) + position = db.Column(db.String) + + diff --git a/app/routes.py b/app/routes.py index 1e864250f..dd8347de9 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,58 +1,60 @@ from flask import Blueprint, jsonify, abort, make_response -class Planet: - def __init__(self, id, name, description, position): - self.id = id - self.name = name - self.description = description - self.position = position - -planets = [ - Planet(1, "Mercury", "Closest to the sun and smallest", "#1"), - Planet(2, "Venus", "The hottest planet of the Solar System", "#2"), - Planet(3, "Earth", "Seventy percent of its surface is cover with water", "#3"), - Planet(4, "Mars", "Known as Red Planet because of iron oxide on its surface", "#4"), - Planet(5, "Jupiter", "The largest of the solar system, it's 2.5 times larger than all the other planets combined", "#5"), - Planet(6, "Saturn", "Known as a gas giant with seven ring systems surrounding it", "#6"), - Planet(7, "Uranus", "It is the coldest planet of the Solar System with temperatures at around -224 degrees Celsius", "#7"), - Planet(8, "Neptune", "Has the fasted wind speeds of any planet, reaching speeds of 2.160 km / 1.314 mi per hour", "#8") - ] - bp = Blueprint("planets", __name__, url_prefix="/planets") -@bp.route("", methods=["GET"]) -def handle_planets(): - planets_response = [] - for planet in planets: - planets_response.append( - { - "id": planet.id, - "name": planet.name, - "description": planet.description, - "position": planet.position - } - ) - return jsonify(planets_response) - -def validate_planet(planet_id): - try: - planet_id = int(planet_id) - except: - abort(make_response({"message":f"Planet {planet_id} invalid"}, 400)) - - for planet in planets: - if planet.id == planet_id: - return planet + + +# class Planet: +# def __init__(self, id, name, description, position): +# self.id = id +# self.name = name +# self.description = description +# self.position = position + +# planets = [ +# Planet(1, "Mercury", "Closest to the sun and smallest", "#1"), +# Planet(2, "Venus", "The hottest planet of the Solar System", "#2"), +# Planet(3, "Earth", "Seventy percent of its surface is cover with water", "#3"), +# Planet(4, "Mars", "Known as Red Planet because of iron oxide on its surface", "#4"), +# Planet(5, "Jupiter", "The largest of the solar system, it's 2.5 times larger than all the other planets combined", "#5"), +# Planet(6, "Saturn", "Known as a gas giant with seven ring systems surrounding it", "#6"), +# Planet(7, "Uranus", "It is the coldest planet of the Solar System with temperatures at around -224 degrees Celsius", "#7"), +# Planet(8, "Neptune", "Has the fasted wind speeds of any planet, reaching speeds of 2.160 km / 1.314 mi per hour", "#8") +# ] + +# @bp.route("", methods=["GET"]) +# def handle_planets(): +# planets_response = [] +# for planet in planets: +# planets_response.append( +# { +# "id": planet.id, +# "name": planet.name, +# "description": planet.description, +# "position": planet.position +# } +# ) +# return jsonify(planets_response) + +# def validate_planet(planet_id): +# try: +# planet_id = int(planet_id) +# except: +# abort(make_response({"message":f"Planet {planet_id} invalid"}, 400)) + +# for planet in planets: +# if planet.id == planet_id: +# return planet - abort(make_response({"message":f"Planet {planet_id} not found"}, 404)) +# abort(make_response({"message":f"Planet {planet_id} not found"}, 404)) -@bp.route("/", methods=["GET"]) -def handle_planet(planet_id): - planet = validate_planet(planet_id) +# @bp.route("/", methods=["GET"]) +# def handle_planet(planet_id): +# planet = validate_planet(planet_id) - return { - "id": planet.id, - "name": planet.name, - "description": planet.description, - "position": planet.position - } +# return { +# "id": planet.id, +# "name": planet.name, +# "description": planet.description, +# "position": planet.position +# } 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/94b66ffc60e6_adds_planet_model.py b/migrations/versions/94b66ffc60e6_adds_planet_model.py new file mode 100644 index 000000000..094efe7d5 --- /dev/null +++ b/migrations/versions/94b66ffc60e6_adds_planet_model.py @@ -0,0 +1,38 @@ +"""adds Planet model + +Revision ID: 94b66ffc60e6 +Revises: +Create Date: 2023-04-28 14:42:16.449873 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '94b66ffc60e6' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column('planet', 'description', + existing_type=sa.TEXT(), + nullable=True) + op.alter_column('planet', 'name', + existing_type=sa.TEXT(), + nullable=True) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column('planet', 'name', + existing_type=sa.TEXT(), + nullable=False) + op.alter_column('planet', 'description', + existing_type=sa.TEXT(), + nullable=False) + # ### end Alembic commands ### From d280b1f328ef6772bb531e7f4b70172a1dfe2fef Mon Sep 17 00:00:00 2001 From: Erina Perez Date: Fri, 28 Apr 2023 13:07:58 -0700 Subject: [PATCH 05/14] Created planet endpoints in Wave 03 --- app/models/planet.py | 2 +- app/routes.py | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/app/models/planet.py b/app/models/planet.py index abdf3a975..626fab2c5 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -1,9 +1,9 @@ from app import db + class Planet(db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String) description = db.Column(db.String) position = db.Column(db.String) - diff --git a/app/routes.py b/app/routes.py index dd8347de9..c60484326 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,8 +1,36 @@ -from flask import Blueprint, jsonify, abort, make_response +from app import db +from app.models.planet import Planet +from flask import Blueprint, jsonify, abort, make_response, request bp = Blueprint("planets", __name__, url_prefix="/planets") +@bp.route("", methods=["POST"]) +def create_planet(): + request_body = request.get_json() + new_planet = Planet(name=request_body["name"], + description=request_body["description"], + position=request_body["position"] + ) + db.session.add(new_planet) + db.session.commit() + + return make_response(f"Planet {new_planet.name} successfully created", 201) + +@bp.route("", methods=["GET"]) +def read_all_planets(): + planets_response = [] + planets = Planet.query.all() + for planet in planets: + planets_response.append( + { + "id": planet.id, + "name": planet.name, + "description": planet.description, + "position": planet.position + } + ) + return jsonify(planets_response) # class Planet: # def __init__(self, id, name, description, position): From 310a27b9a755c023fce7ccefdf4cfbad68253a01 Mon Sep 17 00:00:00 2001 From: Erina Perez Date: Sat, 29 Apr 2023 13:16:41 -0700 Subject: [PATCH 06/14] Added helper function and updated routes --- app/models/planet.py | 7 +++++++ app/routes.py | 10 ++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/models/planet.py b/app/models/planet.py index 626fab2c5..64765e673 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -7,3 +7,10 @@ class Planet(db.Model): description = db.Column(db.String) position = db.Column(db.String) +def make_planet_dict(self): + return dict( + id=self.id, + name=self.name, + description=self.description, + position=self.position + ) \ No newline at end of file diff --git a/app/routes.py b/app/routes.py index c60484326..f04d7bbe1 100644 --- a/app/routes.py +++ b/app/routes.py @@ -22,16 +22,10 @@ def read_all_planets(): planets_response = [] planets = Planet.query.all() for planet in planets: - planets_response.append( - { - "id": planet.id, - "name": planet.name, - "description": planet.description, - "position": planet.position - } - ) + planets_response.append(planet.make_planet_dict) return jsonify(planets_response) + # class Planet: # def __init__(self, id, name, description, position): # self.id = id From e13ac3425ccb05f450ef75d0178a690a489fc3eb Mon Sep 17 00:00:00 2001 From: Barbara Date: Sat, 29 Apr 2023 16:43:57 -0400 Subject: [PATCH 07/14] Completed Wave_03 --- app/models/planet.py | 14 +++++++------- app/routes.py | 16 +++++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/app/models/planet.py b/app/models/planet.py index 64765e673..cb433c977 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -7,10 +7,10 @@ class Planet(db.Model): description = db.Column(db.String) position = db.Column(db.String) -def make_planet_dict(self): - return dict( - id=self.id, - name=self.name, - description=self.description, - position=self.position - ) \ No newline at end of file + def make_planet_dict(self): + return dict( + id=self.id, + name=self.name, + description=self.description, + position=self.position + ) \ No newline at end of file diff --git a/app/routes.py b/app/routes.py index f04d7bbe1..0288289c1 100644 --- a/app/routes.py +++ b/app/routes.py @@ -4,6 +4,14 @@ bp = Blueprint("planets", __name__, url_prefix="/planets") +@bp.route("", methods=["GET"]) +def read_all_planets(): + planets = Planet.query.all() + planets_response = [] + for planet in planets: + planets_response.append(planet.make_planet_dict()) + return jsonify(planets_response) + @bp.route("", methods=["POST"]) def create_planet(): request_body = request.get_json() @@ -17,13 +25,7 @@ def create_planet(): return make_response(f"Planet {new_planet.name} successfully created", 201) -@bp.route("", methods=["GET"]) -def read_all_planets(): - planets_response = [] - planets = Planet.query.all() - for planet in planets: - planets_response.append(planet.make_planet_dict) - return jsonify(planets_response) + # class Planet: From 86e795c4628a33eaf3980ecea88f929f2c02964b Mon Sep 17 00:00:00 2001 From: Erina Perez Date: Mon, 1 May 2023 21:09:02 -0700 Subject: [PATCH 08/14] Recreated migrations --- app/models/planet.py | 2 +- app/routes.py | 2 +- .../94b66ffc60e6_adds_planet_model.py | 38 ------------------- migrations/versions/ad6d66314fdb_.py | 34 +++++++++++++++++ 4 files changed, 36 insertions(+), 40 deletions(-) delete mode 100644 migrations/versions/94b66ffc60e6_adds_planet_model.py create mode 100644 migrations/versions/ad6d66314fdb_.py diff --git a/app/models/planet.py b/app/models/planet.py index cb433c977..2f4f644a5 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -13,4 +13,4 @@ def make_planet_dict(self): name=self.name, description=self.description, position=self.position - ) \ No newline at end of file + ) \ No newline at end of file diff --git a/app/routes.py b/app/routes.py index 0288289c1..29316962b 100644 --- a/app/routes.py +++ b/app/routes.py @@ -23,7 +23,7 @@ def create_planet(): db.session.add(new_planet) db.session.commit() - return make_response(f"Planet {new_planet.name} successfully created", 201) + return make_response(f"Planet {new_planet.name} successfully created", 201) diff --git a/migrations/versions/94b66ffc60e6_adds_planet_model.py b/migrations/versions/94b66ffc60e6_adds_planet_model.py deleted file mode 100644 index 094efe7d5..000000000 --- a/migrations/versions/94b66ffc60e6_adds_planet_model.py +++ /dev/null @@ -1,38 +0,0 @@ -"""adds Planet model - -Revision ID: 94b66ffc60e6 -Revises: -Create Date: 2023-04-28 14:42:16.449873 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = '94b66ffc60e6' -down_revision = None -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.alter_column('planet', 'description', - existing_type=sa.TEXT(), - nullable=True) - op.alter_column('planet', 'name', - existing_type=sa.TEXT(), - nullable=True) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.alter_column('planet', 'name', - existing_type=sa.TEXT(), - nullable=False) - op.alter_column('planet', 'description', - existing_type=sa.TEXT(), - nullable=False) - # ### end Alembic commands ### diff --git a/migrations/versions/ad6d66314fdb_.py b/migrations/versions/ad6d66314fdb_.py new file mode 100644 index 000000000..3b4e2ef5a --- /dev/null +++ b/migrations/versions/ad6d66314fdb_.py @@ -0,0 +1,34 @@ +"""empty message + +Revision ID: ad6d66314fdb +Revises: +Create Date: 2023-05-01 20:08:16.355443 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'ad6d66314fdb' +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.String(), nullable=True), + sa.Column('position', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('planet') + # ### end Alembic commands ### From 568fdb611d38fce8bce2e080d667a317df80a472 Mon Sep 17 00:00:00 2001 From: Barbara Date: Tue, 2 May 2023 15:01:01 -0400 Subject: [PATCH 09/14] Completed Wave_04 --- app/routes.py | 78 ++++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/app/routes.py b/app/routes.py index 29316962b..c64496c78 100644 --- a/app/routes.py +++ b/app/routes.py @@ -25,8 +25,47 @@ def create_planet(): return make_response(f"Planet {new_planet.name} successfully created", 201) +@bp.route("/", methods=["GET"]) +def read_one_planet(planet_id): + planet = validate_planet(planet_id) + return jsonify(planet.make_planet_dict()), 200 +@bp.route("/", methods=["PUT"]) +def update_planet(planet_id): + planet = validate_planet(planet_id) + request_body = request.get_json() + + planet.name=request_body["name"], + planet.description=request_body["description"], + planet.position=request_body["position"] + + db.session.commit() + + return make_response(f"Planet {planet.name} successfully updated", 200) + +@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.name} successfully deleted", 200) + +# helper function +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 # class Planet: # def __init__(self, id, name, description, position): @@ -36,7 +75,7 @@ def create_planet(): # self.position = position # planets = [ -# Planet(1, "Mercury", "Closest to the sun and smallest", "#1"), +# Planet(1, ), # Planet(2, "Venus", "The hottest planet of the Solar System", "#2"), # Planet(3, "Earth", "Seventy percent of its surface is cover with water", "#3"), # Planet(4, "Mars", "Known as Red Planet because of iron oxide on its surface", "#4"), @@ -45,40 +84,3 @@ def create_planet(): # Planet(7, "Uranus", "It is the coldest planet of the Solar System with temperatures at around -224 degrees Celsius", "#7"), # Planet(8, "Neptune", "Has the fasted wind speeds of any planet, reaching speeds of 2.160 km / 1.314 mi per hour", "#8") # ] - -# @bp.route("", methods=["GET"]) -# def handle_planets(): -# planets_response = [] -# for planet in planets: -# planets_response.append( -# { -# "id": planet.id, -# "name": planet.name, -# "description": planet.description, -# "position": planet.position -# } -# ) -# return jsonify(planets_response) - -# def validate_planet(planet_id): -# try: -# planet_id = int(planet_id) -# except: -# abort(make_response({"message":f"Planet {planet_id} invalid"}, 400)) - -# for planet in planets: -# if planet.id == planet_id: -# return planet - -# abort(make_response({"message":f"Planet {planet_id} not found"}, 404)) - -# @bp.route("/", methods=["GET"]) -# def handle_planet(planet_id): -# planet = validate_planet(planet_id) - -# return { -# "id": planet.id, -# "name": planet.name, -# "description": planet.description, -# "position": planet.position -# } From 891d6216a6a5ec217c31abc5e93277c9ca180d21 Mon Sep 17 00:00:00 2001 From: Erina Perez Date: Wed, 3 May 2023 12:25:41 -0700 Subject: [PATCH 10/14] Completed Wave 06 --- app/__init__.py | 21 ++++++++++++++------- app/routes.py | 37 +++++++++++++++++++++++++++---------- tests/__init__.py | 0 tests/conftest.py | 39 +++++++++++++++++++++++++++++++++++++++ tests/test_routes.py | 40 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 17 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/test_routes.py diff --git a/app/__init__.py b/app/__init__.py index a286c810e..15caf3493 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,24 +1,31 @@ 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(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' - - # Import models here - from app.models.planet import Planet + if not test_config: + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get( + "SQLALCHEMY_DATABASE_URI") + else: + app.config["TESTING"] = True + app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False + app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get( + "SQLALCHEMY_TEST_DATABASE_URI") db.init_app(app) migrate.init_app(app, db) - # Register Blueprints + from app.models.planet import Planet + from .routes import bp app.register_blueprint(bp) diff --git a/app/routes.py b/app/routes.py index c64496c78..ea4511f9a 100644 --- a/app/routes.py +++ b/app/routes.py @@ -4,6 +4,7 @@ bp = Blueprint("planets", __name__, url_prefix="/planets") +# READ ALL PLANETS @bp.route("", methods=["GET"]) def read_all_planets(): planets = Planet.query.all() @@ -12,6 +13,7 @@ def read_all_planets(): planets_response.append(planet.make_planet_dict()) return jsonify(planets_response) +# CREATE A PLANET @bp.route("", methods=["POST"]) def create_planet(): request_body = request.get_json() @@ -23,14 +25,16 @@ def create_planet(): db.session.add(new_planet) db.session.commit() - return make_response(f"Planet {new_planet.name} successfully created", 201) + return make_response(jsonify(f"Planet {new_planet.name} successfully created")), 201 +# READ ONE PLANET @bp.route("/", methods=["GET"]) def read_one_planet(planet_id): planet = validate_planet(planet_id) return jsonify(planet.make_planet_dict()), 200 +# UPDATE ONE PLANET @bp.route("/", methods=["PUT"]) def update_planet(planet_id): planet = validate_planet(planet_id) @@ -42,18 +46,19 @@ def update_planet(planet_id): db.session.commit() - return make_response(f"Planet {planet.name} successfully updated", 200) + return make_response(jsonify(f"Planet {update_planet.name} successfully created"), 201) +# DELETE A PLANET @bp.route("/", methods=["DELETE"]) def delete_planet(planet_id): - planet = validate_planet(planet_id) + planet = validate_planet(planet_id) - db.session.delete(planet) - db.session.commit() + db.session.delete(planet) + db.session.commit() - return make_response(f"Planet {planet.name} successfully deleted", 200) + return make_response(f"Planet {planet.name} successfully deleted", 200) -# helper function +# VALIDATE PLANET HELPER FUNCTIONS def validate_planet(planet_id): try: planet_id = int(planet_id) @@ -67,6 +72,7 @@ def validate_planet(planet_id): return planet + # class Planet: # def __init__(self, id, name, description, position): # self.id = id @@ -75,12 +81,23 @@ def validate_planet(planet_id): # self.position = position # planets = [ -# Planet(1, ), -# Planet(2, "Venus", "The hottest planet of the Solar System", "#2"), +# Planet(1, "Mercury", "The smallest planet in our solar system, and the fastest, zooming around the sun every 88 Earth days", #1), +# Planet(2, "Venus", "The hottest planet of the solar system", "#2"), # Planet(3, "Earth", "Seventy percent of its surface is cover with water", "#3"), # Planet(4, "Mars", "Known as Red Planet because of iron oxide on its surface", "#4"), # Planet(5, "Jupiter", "The largest of the solar system, it's 2.5 times larger than all the other planets combined", "#5"), # Planet(6, "Saturn", "Known as a gas giant with seven ring systems surrounding it", "#6"), # Planet(7, "Uranus", "It is the coldest planet of the Solar System with temperatures at around -224 degrees Celsius", "#7"), -# Planet(8, "Neptune", "Has the fasted wind speeds of any planet, reaching speeds of 2.160 km / 1.314 mi per hour", "#8") +# Planet(8, "Neptune", "Has the fastest wind speeds of any planet, reaching up to 2.160 km / 1,314 mi per hour", "#8") # ] + + +# JSON format: + +# { + # "name": "Mercury", + # "description": "The smallest planet in our solar system, and the fastest, zooming around the sun every 88 Earth days", + # "position": "#1"} + + +# get one test: response = client.get(f"/cats/{one_cat.id}"") because in the fixture, one_cat(app) return cat === returns one cat \ No newline at end of file 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..daff08d18 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,39 @@ +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() + + +@pytest.fixture +def two_saved_planets(app): + # Arrange + test_blue_planet = Planet(name="Blueto", + description="Watr 4evr", + position="#100") + test_purple_planet = Planet(name="Purpley", + description="Ice 4evr", + position="#70") + + db.session.add_all([test_blue_planet, test_purple_planet]) + db.session.commit() diff --git a/tests/test_routes.py b/tests/test_routes.py new file mode 100644 index 000000000..d66151c3f --- /dev/null +++ b/tests/test_routes.py @@ -0,0 +1,40 @@ +# TEST GET ALL PLANETS +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 == [] + +# TEST ONE PLANET +def test_get_one_planet(client, two_saved_planets): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == { + "id": 1, + "name": "Blueto", + "description": "Watr 4evr", + "position": "#100" + } + +# TEST CREATE ONE PLANET +def test_create_one_planet(client): + # Act + response = client.post("/planets", json={ + "name": "Pink Star", + "description": "Surface made of pink glitter", + "position": "#68" + }) + response_body = response.get_json() + + # Assert + assert response.status_code == 201 + assert response_body == "Planet Pink Star successfully created" + + From e0aa470e53b078898ef98e282ff45fc437086515 Mon Sep 17 00:00:00 2001 From: Barbara Date: Thu, 4 May 2023 18:16:21 -0400 Subject: [PATCH 11/14] Completed Wave_05, Wave_07 and refactor --- app/__init__.py | 2 +- app/models/planet.py | 24 ++++++--- app/routes.py | 99 +++++++++++++---------------------- tests/test_models.py | 121 +++++++++++++++++++++++++++++++++++++++++++ tests/test_routes.py | 107 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 282 insertions(+), 71 deletions(-) create mode 100644 tests/test_models.py diff --git a/app/__init__.py b/app/__init__.py index 15caf3493..b60e768c4 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -24,7 +24,7 @@ def create_app(test_config=None): db.init_app(app) migrate.init_app(app, db) - from app.models.planet import Planet + # from app.models.planet import Planet from .routes import bp app.register_blueprint(bp) diff --git a/app/models/planet.py b/app/models/planet.py index 2f4f644a5..008a9d00a 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -1,16 +1,24 @@ from app import db - class Planet(db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String) description = db.Column(db.String) position = db.Column(db.String) - def make_planet_dict(self): - return dict( - id=self.id, - name=self.name, - description=self.description, - position=self.position - ) \ No newline at end of file + def to_dict(self): + planet_as_dic = {} + planet_as_dic["id"] = self.id + planet_as_dic["name"] = self.name + planet_as_dic["description"] = self.description + planet_as_dic["position"] = self.position + + return planet_as_dic + + @classmethod + def from_dict(cls, planet_data): + new_planet = Planet(name=planet_data["name"], + description=planet_data["description"], + position=planet_data["position"]) + + return new_planet diff --git a/app/routes.py b/app/routes.py index ea4511f9a..be5ffe78b 100644 --- a/app/routes.py +++ b/app/routes.py @@ -4,40 +4,58 @@ bp = Blueprint("planets", __name__, url_prefix="/planets") -# READ ALL PLANETS -@bp.route("", methods=["GET"]) -def read_all_planets(): - planets = Planet.query.all() - planets_response = [] - for planet in planets: - planets_response.append(planet.make_planet_dict()) - return jsonify(planets_response) +# VALIDATE PLANET HELPER FUNCTIONS +def validate_model(cls, model_id): + try: + model_id = int(model_id) + except: + abort(make_response({"message":f"{cls.__name__} {model_id} invalid"}, 400)) + + model = cls.query.get(model_id) + + if not model: + abort(make_response({"message":f"{cls.__name__} {model_id} not found"}, 404)) + + return model # CREATE A PLANET @bp.route("", methods=["POST"]) def create_planet(): request_body = request.get_json() - new_planet = Planet(name=request_body["name"], - description=request_body["description"], - position=request_body["position"] - ) + new_planet = Planet.from_dict(request_body) db.session.add(new_planet) db.session.commit() return make_response(jsonify(f"Planet {new_planet.name} successfully created")), 201 + +# READ ALL PLANETS +@bp.route("", methods=["GET"]) +def read_all_planets(): + name_query = request.args.get("name") + + if name_query: + planets = Planet.query.filter_by(name=name_query) + else: + planets = Planet.query.all() + + planets_response = [] + for planet in planets: + planets_response.append(planet.to_dict()) + return jsonify(planets_response) + + # READ ONE PLANET @bp.route("/", methods=["GET"]) def read_one_planet(planet_id): - planet = validate_planet(planet_id) - - return jsonify(planet.make_planet_dict()), 200 + planet = validate_model(Planet, planet_id) + return planet.to_dict() # UPDATE ONE PLANET @bp.route("/", methods=["PUT"]) def update_planet(planet_id): - planet = validate_planet(planet_id) + planet = validate_model(Planet, planet_id) request_body = request.get_json() planet.name=request_body["name"], @@ -46,58 +64,15 @@ def update_planet(planet_id): db.session.commit() - return make_response(jsonify(f"Planet {update_planet.name} successfully created"), 201) + return make_response(jsonify(f"Planet {update_planet.name} successfully updated")) # DELETE A PLANET @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() - return make_response(f"Planet {planet.name} successfully deleted", 200) - -# VALIDATE PLANET HELPER FUNCTIONS -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 - - -# class Planet: -# def __init__(self, id, name, description, position): -# self.id = id -# self.name = name -# self.description = description -# self.position = position - -# planets = [ -# Planet(1, "Mercury", "The smallest planet in our solar system, and the fastest, zooming around the sun every 88 Earth days", #1), -# Planet(2, "Venus", "The hottest planet of the solar system", "#2"), -# Planet(3, "Earth", "Seventy percent of its surface is cover with water", "#3"), -# Planet(4, "Mars", "Known as Red Planet because of iron oxide on its surface", "#4"), -# Planet(5, "Jupiter", "The largest of the solar system, it's 2.5 times larger than all the other planets combined", "#5"), -# Planet(6, "Saturn", "Known as a gas giant with seven ring systems surrounding it", "#6"), -# Planet(7, "Uranus", "It is the coldest planet of the Solar System with temperatures at around -224 degrees Celsius", "#7"), -# Planet(8, "Neptune", "Has the fastest wind speeds of any planet, reaching up to 2.160 km / 1,314 mi per hour", "#8") -# ] - - -# JSON format: - -# { - # "name": "Mercury", - # "description": "The smallest planet in our solar system, and the fastest, zooming around the sun every 88 Earth days", - # "position": "#1"} - + return make_response(jsonify(f"Planet {planet.name} successfully deleted")) -# get one test: response = client.get(f"/cats/{one_cat.id}"") because in the fixture, one_cat(app) return cat === returns one cat \ No newline at end of file diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 000000000..391626de3 --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,121 @@ +from app.models.planet import Planet +import pytest + +def test_to_dict_no_missing_data(): + # Arrange + test_data = Planet(id = 2, + name="Arrakis", + description="Spicy", + position="#82") + + # Act + result = test_data.to_dict() + + # Assert + assert len(result) == 4 + assert result["id"] == 2 + assert result["name"] == "Arrakis" + assert result["description"] == "Spicy" + assert result["position"] == "#82" + +def test_to_dict_missing_id(): + # Arrange + test_data = Planet(name="Arrakis", + description="Spicy", + position="#82") + + # Act + result = test_data.to_dict() + + # Assert + assert len(result) == 4 + assert result["id"] is None + assert result["name"] == "Arrakis" + assert result["description"] == "Spicy" + assert result["position"] == "#82" + +def test_to_dict_missing_name(): + # Arrange + test_data = Planet(id=1, + description="Spicy", + position="#82") + + # Act + result = test_data.to_dict() + + # Assert + assert len(result) == 4 + assert result["id"] == 1 + assert result["name"] is None + assert result["description"] == "Spicy" + assert result["position"] == "#82" + +def test_to_dict_missing_description(): + # Arrange + test_data = Planet(id = 1, + name="Arrakis") + + # Act + result = test_data.to_dict() + + # Assert + assert len(result) == 4 + assert result["id"] == 1 + assert result["name"] == "Arrakis" + assert result["description"] is None + assert result["position"] == None + + +# new tests for from_dict +def test_from_dict_returns_planet(): + # Arrange + planet_data = { + "name": "New Planet", + "description": "The mild planet", + "position": "#91" + } + + # Act + new_planet = Planet.from_dict(planet_data) + + # Assert + assert new_planet.name == "New Planet" + assert new_planet.description == "The mild planet" + assert new_planet.position == "#91" + +def test_from_dict_with_no_name(): + # Arrange + planet_data = { + "description": "The mild planet" + } + + # Act & Assert + with pytest.raises(KeyError, match = 'name'): + new_planet = Planet.from_dict(planet_data) + +def test_from_dict_with_no_description(): + # Arrange + planet_data = { + "name": "New planet" + } + + # Act & Assert + with pytest.raises(KeyError, match = 'description'): + new_planet = Planet.from_dict(planet_data) + +def test_from_dict_with_extra_keys(): + # Arrange + planet_data = { + "extra": "some stuff", + "name": "New planet", + "description": "The mild planet", + "position": "#40" + } + + # Act + new_planet = Planet.from_dict(planet_data) + + # Assert + assert new_planet.name == "New planet" + assert new_planet.description == "The mild planet" + assert new_planet.position == "#40" \ No newline at end of file diff --git a/tests/test_routes.py b/tests/test_routes.py index d66151c3f..471ac9d36 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -1,3 +1,5 @@ +import pytest + # TEST GET ALL PLANETS def test_get_all_planets_with_no_records(client): # Act @@ -38,3 +40,108 @@ def test_create_one_planet(client): assert response_body == "Planet Pink Star successfully created" +def test_get_all_planets_with_three_records(client, two_saved_planets): + # Act + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert len(response_body) == 2 + assert response_body[0] == { + "id": 1, + "name": "Blueto", + "description": "Watr 4evr", + "position": "#100" + } + assert response_body[1] == { + "id": 2, + "name": "Purpley", + "description": "Ice 4evr", + "position": "#70" + } + +def test_get_all_planets_with_name_query_matching_none(client, two_saved_planets): + # Act + data = {'name': 'Pluto'} + response = client.get("/planets", query_string = data) + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == [] + +def test_get_all_planets_with_name_query_matching_one(client, two_saved_planets): + # Act + data = {'name': 'Blueto'} + response = client.get("/planets", query_string = data) + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert len(response_body) == 1 + assert response_body[0] == { + "id": 1, + "name": "Blueto", + "description": "Watr 4evr", + "position": "#100" + } + +def test_get_one_planet_id_not_found(client, two_saved_planets): + # Act + response = client.get("/planets/10") + response_body = response.get_json() + + # Assert + assert response.status_code == 404 + assert response_body == {"message":"Planet 10 not found"} + +def test_get_one_planet_id_invalid(client, two_saved_planets): + # Act + response = client.get("/planets/pluto") + response_body = response.get_json() + + # Assert + assert response.status_code == 400 + assert response_body == {"message":"Planet pluto invalid"} + + +# new test cases for create_planet + +def test_create_one_planet_no_name(client): + # Arrange + test_data = {"description": "The mild planet"} + + # Act & Assert + with pytest.raises(KeyError, match='name'): + response = client.post("/planets", json=test_data) + +def test_create_one_planet_no_description(client): + # Arrange + test_data = {"name": "New planet"} + + # Act & Assert + with pytest.raises(KeyError, match = 'description'): + response = client.post("/planets", json=test_data) + +def test_create_one_planet_with_extra_keys(client, two_saved_planets): + # Arrange + test_data = { + "extra": "some stuff", + "name": "New planet", + "description": "The mild planet", + "position": "#87", + } + + # Act + response = client.post("/planets", json=test_data) + response_body = response.get_json() + + # Assert + assert response.status_code == 201 + assert response_body == "Planet New planet successfully created" + + + + + From c5c0a181b4e45d0d25ae85d7a881272e115eb689 Mon Sep 17 00:00:00 2001 From: Barbara Date: Thu, 4 May 2023 18:29:59 -0400 Subject: [PATCH 12/14] Final clean ups --- app/__init__.py | 2 -- app/routes.py | 6 ++---- tests/test_models.py | 2 +- tests/test_routes.py | 7 +------ 4 files changed, 4 insertions(+), 13 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index b60e768c4..43637d20d 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -24,8 +24,6 @@ def create_app(test_config=None): db.init_app(app) migrate.init_app(app, db) - # from app.models.planet import Planet - from .routes import bp app.register_blueprint(bp) diff --git a/app/routes.py b/app/routes.py index be5ffe78b..0a2fd49f3 100644 --- a/app/routes.py +++ b/app/routes.py @@ -29,7 +29,6 @@ def create_planet(): return make_response(jsonify(f"Planet {new_planet.name} successfully created")), 201 - # READ ALL PLANETS @bp.route("", methods=["GET"]) def read_all_planets(): @@ -64,7 +63,7 @@ def update_planet(planet_id): db.session.commit() - return make_response(jsonify(f"Planet {update_planet.name} successfully updated")) + return make_response(jsonify(f"Planet {planet.name} successfully updated")) # DELETE A PLANET @bp.route("/", methods=["DELETE"]) @@ -74,5 +73,4 @@ def delete_planet(planet_id): db.session.delete(planet) db.session.commit() - return make_response(jsonify(f"Planet {planet.name} successfully deleted")) - + return make_response(jsonify(f"Planet {planet.name} successfully deleted")) \ No newline at end of file diff --git a/tests/test_models.py b/tests/test_models.py index 391626de3..ec0766c79 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -7,7 +7,7 @@ def test_to_dict_no_missing_data(): name="Arrakis", description="Spicy", position="#82") - + # Act result = test_data.to_dict() diff --git a/tests/test_routes.py b/tests/test_routes.py index 471ac9d36..e729eed71 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -139,9 +139,4 @@ def test_create_one_planet_with_extra_keys(client, two_saved_planets): # Assert assert response.status_code == 201 - assert response_body == "Planet New planet successfully created" - - - - - + assert response_body == "Planet New planet successfully created" \ No newline at end of file From 865a2ce291046d14c5f420cfd98ad5252e797edd Mon Sep 17 00:00:00 2001 From: Erina Perez Date: Tue, 9 May 2023 11:03:11 -0700 Subject: [PATCH 13/14] Installed gunicorn --- requirements.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/requirements.txt b/requirements.txt index ae59e7b55..f4ff77124 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,14 +4,20 @@ blinker==1.4 certifi==2020.12.5 chardet==4.0.0 click==7.1.2 +coverage==7.2.3 +exceptiongroup==1.1.1 Flask==1.1.2 Flask-Migrate==2.6.0 Flask-SQLAlchemy==2.4.4 +gunicorn==20.1.0 idna==2.10 +iniconfig==2.0.0 itsdangerous==1.1.0 Jinja2==2.11.3 Mako==1.1.4 MarkupSafe==1.1.1 +packaging==23.1 +pluggy==1.0.0 psycopg2-binary==2.9.5 pycodestyle==2.6.0 pytest==7.3.1 @@ -23,5 +29,6 @@ requests==2.25.1 six==1.15.0 SQLAlchemy==1.3.23 toml==0.10.2 +tomli==2.0.1 urllib3==1.26.4 Werkzeug==1.0.1 From 5dc291e7f8a58a42e263c4cd7d29ae7fdef46228 Mon Sep 17 00:00:00 2001 From: Erina Perez Date: Tue, 9 May 2023 21:44:39 -0700 Subject: [PATCH 14/14] Completed Render updates --- app/__init__.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 43637d20d..80eec2ced 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -8,17 +8,20 @@ migrate = Migrate() load_dotenv() + def create_app(test_config=None): + # __name__ stores the name of the module we're in app = Flask(__name__) + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False if not test_config: - app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get( - "SQLALCHEMY_DATABASE_URI") + "RENDER_DATABASE_URI") + # app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get( + # "SQLALCHEMY_DATABASE_URI") else: - app.config["TESTING"] = True - app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False - app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get( + app.config['TESTING'] = True + app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get( "SQLALCHEMY_TEST_DATABASE_URI") db.init_app(app)