From 3f1c6829cd8bc20faa5fcc093093d2460f90d3f2 Mon Sep 17 00:00:00 2001 From: Aisha Date: Mon, 24 Apr 2023 14:07:51 -0500 Subject: [PATCH 01/17] Agreements, Aisha's signature --- coworking_agreement.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/coworking_agreement.md b/coworking_agreement.md index 463598c27..36418c462 100644 --- a/coworking_agreement.md +++ b/coworking_agreement.md @@ -4,15 +4,19 @@ Talk through each section with your partner. Add notes on what you discussed and ## Accessibility Needs *What does each team member need access to in order to succeed and show up the best they can?* +Go slowly together through instructions, screen share as much as possible ## Collaboration vs. individual work expectations *Clarify your collaboration expectations- does your group want to write code together all of the time? Or divide work to do independently, then come together to share accomplishments? What tools and technologies can help your collaboration?* +Work independently, collaborate on zoom as much as needed ## Learning Style *How does each team member learn best in project settings?* +refer to Q2 ## Preferred Feedback Style *How does each team member best receive feedback?* +Included in the collabrating/discussion ## One Team Communication Skill to Improve *What is a teamwork-related skill you want to work on?* @@ -21,5 +25,5 @@ Talk through each section with your partner. Add notes on what you discussed and *Other co-working agreements that were not captured in the above sections.* ## Signatures -______________ _______________ -Date: _________ +Aisha Mohamed _______________ +Date: 4/24/23 From 0ef2058cd64ad6659de8f7321e64a126cb9c88d2 Mon Sep 17 00:00:00 2001 From: Aisha Date: Mon, 24 Apr 2023 17:51:57 -0500 Subject: [PATCH 02/17] Can handle returning for id in database --- app/__init__.py | 3 +++ app/routes.py | 28 +++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/app/__init__.py b/app/__init__.py index 70b4cabfe..2e624ccf9 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..5b514c46b 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,2 +1,28 @@ -from flask import Blueprint +from flask import Blueprint, jsonify +class Planet: + def __init__(self, id, name, description): + self.id = id + self.name = name + self.description = description + + +planets = [ + Planet(1, "Mercury", "dark gray"), + Planet(2, "Venus", "light yellow"), + Planet(3, "Earth", "blue and green") +] + +bp = Blueprint("planets", __name__, url_prefix="/planets") + +@bp.route("/", methods = ["GET"]) + +def handle_planet(planet_id): + planet_id = int(planet_id) + for planet in planets: + if planet.id == planet_id: + return (dict( + id = planet.id, + name= planet.name, + description= planet.description + )) From 96016bded1248a53dd59ae495ab98323c3ab1351 Mon Sep 17 00:00:00 2001 From: Aisha Date: Mon, 24 Apr 2023 17:54:18 -0500 Subject: [PATCH 03/17] Returns invalid 400 error for non-int --- app/routes.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/routes.py b/app/routes.py index 5b514c46b..9c305697f 100644 --- a/app/routes.py +++ b/app/routes.py @@ -18,7 +18,11 @@ def __init__(self, id, name, description): @bp.route("/", methods = ["GET"]) def handle_planet(planet_id): - planet_id = int(planet_id) + try: + planet_id = int(planet_id) + except: + return {"message": f"planet {planet_id} not valid"}, 400 + for planet in planets: if planet.id == planet_id: return (dict( From 7646f039d436590b3acb7f4690d41d2848a5a8de Mon Sep 17 00:00:00 2001 From: Aisha Date: Mon, 24 Apr 2023 17:55:51 -0500 Subject: [PATCH 04/17] Returns not found 404 error --- app/routes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/routes.py b/app/routes.py index 9c305697f..8c1622173 100644 --- a/app/routes.py +++ b/app/routes.py @@ -30,3 +30,5 @@ def handle_planet(planet_id): name= planet.name, description= planet.description )) + + return {"message": f"planet {planet_id} not found"}, 404 \ No newline at end of file From 04111a55fb9cef40530780f46ee2a80f004912d6 Mon Sep 17 00:00:00 2001 From: Aisha Date: Mon, 24 Apr 2023 18:00:49 -0500 Subject: [PATCH 05/17] added helper fucntion to validate id --- app/routes.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/app/routes.py b/app/routes.py index 8c1622173..b20548edf 100644 --- a/app/routes.py +++ b/app/routes.py @@ -17,7 +17,7 @@ def __init__(self, id, name, description): @bp.route("/", methods = ["GET"]) -def handle_planet(planet_id): +def validate_planet(planet_id): try: planet_id = int(planet_id) except: @@ -25,10 +25,15 @@ def handle_planet(planet_id): for planet in planets: if planet.id == planet_id: - return (dict( + return planet + + return {"message": f"planet {planet_id} not found"}, 404 + + +def handle_planet(planet_id): + planet = validate_planet(planet_id) + return dict( id = planet.id, name= planet.name, description= planet.description - )) - - return {"message": f"planet {planet_id} not found"}, 404 \ No newline at end of file + ) \ No newline at end of file From de6098c884aedca590a6061332ccb0630b1abf10 Mon Sep 17 00:00:00 2001 From: Aisha Date: Mon, 24 Apr 2023 18:02:42 -0500 Subject: [PATCH 06/17] added a helper fucntion to make a dict for return --- app/routes.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/routes.py b/app/routes.py index b20548edf..fe9e935ab 100644 --- a/app/routes.py +++ b/app/routes.py @@ -28,12 +28,15 @@ def validate_planet(planet_id): return planet return {"message": f"planet {planet_id} not found"}, 404 - -def handle_planet(planet_id): - planet = validate_planet(planet_id) +def make_dict(planet): return dict( id = planet.id, name= planet.name, description= planet.description - ) \ No newline at end of file + ) + + +def handle_planet(planet_id): + planet = validate_planet(planet_id) + return make_dict(planet) \ No newline at end of file From a9f0f8d84dac1226fa141a421fc09809ef71c103 Mon Sep 17 00:00:00 2001 From: Aisha Date: Mon, 24 Apr 2023 18:07:45 -0500 Subject: [PATCH 07/17] changed error messages from return to abort(make_response()) --- app/routes.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/routes.py b/app/routes.py index fe9e935ab..137d9c226 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): @@ -21,13 +21,13 @@ def validate_planet(planet_id): try: planet_id = int(planet_id) except: - return {"message": f"planet {planet_id} not valid"}, 400 + abort(make_response({"message": f"planet {planet_id} not valid"}, 400)) for planet in planets: if planet.id == planet_id: return planet - return {"message": f"planet {planet_id} not found"}, 404 + abort(make_response({"message": f"planet {planet_id} not found"}, 404)) def make_dict(planet): return dict( @@ -35,7 +35,6 @@ def make_dict(planet): name= planet.name, description= planet.description ) - def handle_planet(planet_id): planet = validate_planet(planet_id) From 016f76f18445254a0477b22b3cf75123df154a32 Mon Sep 17 00:00:00 2001 From: Abby Castillo Date: Tue, 25 Apr 2023 16:27:22 -0700 Subject: [PATCH 08/17] fleshed out wave_01. expanded Planet class, expanded planets list, wrote handle_planets(), and moved the GET planet_id route next to handle_planet() --- app/routes.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/app/routes.py b/app/routes.py index 137d9c226..5f8320b0f 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,21 +1,34 @@ from flask import Blueprint, jsonify, abort, make_response class Planet: - def __init__(self, id, name, description): + def __init__(self, id, name, description, chemical_composition): self.id = id self.name = name self.description = description + self.composition = chemical_composition planets = [ - Planet(1, "Mercury", "dark gray"), - Planet(2, "Venus", "light yellow"), - Planet(3, "Earth", "blue and green") + Planet(1, "Mercury", "dark gray", "terrestrial"), + Planet(2, "Venus", "light yellow", "terrestrial"), + Planet(3, "Earth", "blue and green", "terrestrial"), + Planet(4, "Mars", "red", "terrestrial"), + Planet(5, "Jupiter", "orange and brown", "gas giant") ] bp = Blueprint("planets", __name__, url_prefix="/planets") -@bp.route("/", methods = ["GET"]) +@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, + "chemical composition": planet.composition + }) + return jsonify(planets_response) def validate_planet(planet_id): try: @@ -33,9 +46,11 @@ def make_dict(planet): return dict( id = planet.id, name= planet.name, - description= planet.description + description= planet.description, + composition= planet.composition ) +@bp.route("/", methods = ["GET"]) def handle_planet(planet_id): planet = validate_planet(planet_id) return make_dict(planet) \ No newline at end of file From 5b1231057301f9930dde501a4702e9461b39c492 Mon Sep 17 00:00:00 2001 From: Aisha Date: Fri, 28 Apr 2023 13:32:03 -0500 Subject: [PATCH 09/17] Class set up --- app/__init__.py | 12 +++++ app/models/planet.py | 15 ++++++ app/routes.py | 103 ++++++++++++++++++++------------------ migrations/README | 1 + migrations/alembic.ini | 45 +++++++++++++++++ migrations/env.py | 96 +++++++++++++++++++++++++++++++++++ migrations/script.py.mako | 24 +++++++++ 7 files changed, 246 insertions(+), 50 deletions(-) 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 diff --git a/app/__init__.py b/app/__init__.py index 2e624ccf9..539e3594d 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,9 +1,21 @@ 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.planet import Planet + from .routes import bp app.register_blueprint(bp) diff --git a/app/models/planet.py b/app/models/planet.py new file mode 100644 index 000000000..e1c8a2566 --- /dev/null +++ b/app/models/planet.py @@ -0,0 +1,15 @@ +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) + composition = db.Column(db.String) + + def to_dict(self): + return { + "id": self.id, + "name": self.name, + "description": self.description, + "composition": self.composition + } diff --git a/app/routes.py b/app/routes.py index 5f8320b0f..f8436024e 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,56 +1,59 @@ from flask import Blueprint, jsonify, abort, make_response -class Planet: - def __init__(self, id, name, description, chemical_composition): - self.id = id - self.name = name - self.description = description - self.composition = chemical_composition - - -planets = [ - Planet(1, "Mercury", "dark gray", "terrestrial"), - Planet(2, "Venus", "light yellow", "terrestrial"), - Planet(3, "Earth", "blue and green", "terrestrial"), - Planet(4, "Mars", "red", "terrestrial"), - Planet(5, "Jupiter", "orange and brown", "gas giant") -] -bp = Blueprint("planets", __name__, url_prefix="/planets") +# class Planet: +# def __init__(self, id, name, description, chemical_composition): +# self.id = id +# self.name = name +# self.description = description +# self.composition = chemical_composition + -@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, - "chemical composition": planet.composition - }) - return jsonify(planets_response) - -def validate_planet(planet_id): - try: - planet_id = int(planet_id) - except: - abort(make_response({"message": f"planet {planet_id} not valid"}, 400)) +# planets = [ +# Planet(1, "Mercury", "dark gray", "terrestrial"), +# Planet(2, "Venus", "light yellow", "terrestrial"), +# Planet(3, "Earth", "blue and green", "terrestrial"), +# Planet(4, "Mars", "red", "terrestrial"), +# Planet(5, "Jupiter", "orange and brown", "gas giant") +# ] + +bp = Blueprint("planets", __name__, url_prefix="/planets") +# @bp.route("",methods=["GET"]) + + +# @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, +# "chemical composition": planet.composition +# }) +# return jsonify(planets_response) + +# def validate_planet(planet_id): +# try: +# planet_id = int(planet_id) +# except: +# abort(make_response({"message": f"planet {planet_id} not valid"}, 400)) - for planet in planets: - if planet.id == planet_id: - return planet +# for planet in planets: +# if planet.id == planet_id: +# return planet - abort(make_response({"message": f"planet {planet_id} not found"}, 404)) - -def make_dict(planet): - return dict( - id = planet.id, - name= planet.name, - description= planet.description, - composition= planet.composition - ) - -@bp.route("/", methods = ["GET"]) -def handle_planet(planet_id): - planet = validate_planet(planet_id) - return make_dict(planet) \ No newline at end of file +# abort(make_response({"message": f"planet {planet_id} not found"}, 404)) + +# def make_dict(planet): +# return dict( +# id = planet.id, +# name= planet.name, +# description= planet.description, +# composition= planet.composition +# ) + +# @bp.route("/", methods = ["GET"]) +# def handle_planet(planet_id): +# planet = validate_planet(planet_id) +# return make_dict(planet) \ No newline at end of file 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 b292d23b425166077e39715e8b041a5af6fa807d Mon Sep 17 00:00:00 2001 From: Aisha Date: Fri, 28 Apr 2023 13:56:57 -0500 Subject: [PATCH 10/17] final version from friday activity --- .../52ece3cb3316_adds_planet_model.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 migrations/versions/52ece3cb3316_adds_planet_model.py diff --git a/migrations/versions/52ece3cb3316_adds_planet_model.py b/migrations/versions/52ece3cb3316_adds_planet_model.py new file mode 100644 index 000000000..67df3b83d --- /dev/null +++ b/migrations/versions/52ece3cb3316_adds_planet_model.py @@ -0,0 +1,34 @@ +"""adds Planet model + +Revision ID: 52ece3cb3316 +Revises: +Create Date: 2023-04-28 13:43:39.794317 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '52ece3cb3316' +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('composition', 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 856f614368099f19e5cc6e0875af7ec9f0aaf07a Mon Sep 17 00:00:00 2001 From: Abby Castillo Date: Wed, 3 May 2023 11:44:03 -0700 Subject: [PATCH 11/17] finished wave 3 :) --- app/routes.py | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/app/routes.py b/app/routes.py index f8436024e..739048d0e 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,13 +1,6 @@ -from flask import Blueprint, jsonify, abort, make_response - - -# class Planet: -# def __init__(self, id, name, description, chemical_composition): -# self.id = id -# self.name = name -# self.description = description -# self.composition = chemical_composition - +from flask import Blueprint, jsonify, abort, make_response, request +from app.models.planet import Planet +from app import db # planets = [ # Planet(1, "Mercury", "dark gray", "terrestrial"), @@ -20,6 +13,29 @@ bp = Blueprint("planets", __name__, url_prefix="/planets") # @bp.route("",methods=["GET"]) +@bp.route("", methods=["POST"]) +def create_planet(): + request_body=request.get_json() + + new_planet = Planet( + name=request_body["name"], + description=request_body["description"], + composition=request_body["composition"] + ) + + db.session.add(new_planet) + db.session.commit() + + return make_response(f"Planet {new_planet.name} successfully created", 201) + +@bp.route("", methods=["GET"]) +def get_all_planets(): + planets = Planet.query.all() + planets_list = [] + for planet in planets: + planets_list.append(planet.to_dict()) + + return jsonify(planets_list), 200 # @bp.route("", methods=["GET"]) # def handle_planets(): From c59677e0a733acba03dfe3dee8271aef5c46e480 Mon Sep 17 00:00:00 2001 From: Abby Castillo Date: Thu, 4 May 2023 11:38:59 -0700 Subject: [PATCH 12/17] finished wave 4 --- app/routes.py | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/app/routes.py b/app/routes.py index 739048d0e..fb87d524e 100644 --- a/app/routes.py +++ b/app/routes.py @@ -13,6 +13,27 @@ bp = Blueprint("planets", __name__, url_prefix="/planets") # @bp.route("",methods=["GET"]) +# helper function +def validate_planet(planet_id): + try: + planet_id = int(planet_id) + except: + abort(make_response({"message": f"planet {planet_id} not valid"}, 400)) + + planet = Planet.query.get(planet_id) + + if not planet: + abort(make_response({"message": f"planet {planet_id} not found"}, 404)) + + return planet + +# routes +@bp.route("/", methods=["GET"]) +def get_one_planet(id): + planet = validate_planet(id) + + return planet.to_dict(), 200 + @bp.route("", methods=["POST"]) def create_planet(): request_body=request.get_json() @@ -49,18 +70,6 @@ def get_all_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} not valid"}, 400)) - -# for planet in planets: -# if planet.id == planet_id: -# return planet - -# abort(make_response({"message": f"planet {planet_id} not found"}, 404)) - # def make_dict(planet): # return dict( # id = planet.id, From ad0faecf67db9e870ed9e0023afc9022c10cb5a0 Mon Sep 17 00:00:00 2001 From: Aisha Date: Thu, 4 May 2023 17:04:28 -0500 Subject: [PATCH 13/17] update single planet completed --- app/routes.py | 13 +++++++ .../f8516ad14cf2_updates_planet_model.py | 34 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 migrations/versions/f8516ad14cf2_updates_planet_model.py diff --git a/app/routes.py b/app/routes.py index fb87d524e..03b2fda85 100644 --- a/app/routes.py +++ b/app/routes.py @@ -34,6 +34,19 @@ def get_one_planet(id): return planet.to_dict(), 200 +@bp.route("/", methods =["PUT"]) +def update_one_planet(id): + planet = validate_planet(id) + request_body = request.get_json() + + planet.name = request_body["name"] + planet.description = request_body["description"] + planet.composition = request_body["composition"] + + db.session.commit() + + return make_response(f"Planet {planet.name} successfully updated", 200) + @bp.route("", methods=["POST"]) def create_planet(): request_body=request.get_json() diff --git a/migrations/versions/f8516ad14cf2_updates_planet_model.py b/migrations/versions/f8516ad14cf2_updates_planet_model.py new file mode 100644 index 000000000..6deed102a --- /dev/null +++ b/migrations/versions/f8516ad14cf2_updates_planet_model.py @@ -0,0 +1,34 @@ +"""updates planet model + +Revision ID: f8516ad14cf2 +Revises: 52ece3cb3316 +Create Date: 2023-05-04 16:57:29.569074 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'f8516ad14cf2' +down_revision = '52ece3cb3316' +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('composition', 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 6343e369df9fff5da0affa0b438913fbc4e2d959 Mon Sep 17 00:00:00 2001 From: Aisha Date: Thu, 4 May 2023 17:11:02 -0500 Subject: [PATCH 14/17] Wave 4 completed --- app/routes.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/routes.py b/app/routes.py index 03b2fda85..b5f1f29c1 100644 --- a/app/routes.py +++ b/app/routes.py @@ -47,6 +47,15 @@ def update_one_planet(id): return make_response(f"Planet {planet.name} successfully updated", 200) +@bp.route("/", methods = ["DELETE"]) +def delete_one_planet(id): + planet = validate_planet(id) + + db.session.delete(planet) + db.session.commit() + + return make_response(f"Planet {planet.name} successfully deleted", 200) + @bp.route("", methods=["POST"]) def create_planet(): request_body=request.get_json() From ae0411000993e7df87935c126ad7c8c5fbb550c6 Mon Sep 17 00:00:00 2001 From: Abby Castillo Date: Thu, 4 May 2023 15:56:21 -0700 Subject: [PATCH 15/17] finished wave 6 up to test 3 --- app/__init__.py | 18 ++++++++++++--- tests/__init__.py | 0 tests/conftest.py | 38 ++++++++++++++++++++++++++++++++ tests/test_routes.py | 52 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 3 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 539e3594d..9718c19a8 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,16 +1,28 @@ 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' + # 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_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) 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..ce5d38800 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,38 @@ +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): + first_planet = Planet(name="first planet", + description="the first one", + composition="first") + second_planet = Planet(name="second planet", + description="the second one", + composition="second") + + db.session.add_all([first_planet, second_planet]) + db.session.commit() \ No newline at end of file diff --git a/tests/test_routes.py b/tests/test_routes.py new file mode 100644 index 000000000..1682bca82 --- /dev/null +++ b/tests/test_routes.py @@ -0,0 +1,52 @@ +from werkzeug.exceptions import HTTPException +# from app.routes import validate_book +import pytest + +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 == [] + +def test_get_first_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": "first planet", + "description": "the first one", + "composition": "first" + } + +def test_get_first_planet_from_empty_database(client): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 404 + assert response_body == {"message": f"planet 1 not found"} + +def test_get_all_planets(client, two_saved_planets): + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == [ + {"id": 1, + "name": "first planet", + "description": "the first one", + "composition": "first"}, + {"id": 2, + "name": "second planet", + "description": "the second one", + "composition": "second"} + ] \ No newline at end of file From 4777cfe5186c6b4a2446ba8fd5579000767f1358 Mon Sep 17 00:00:00 2001 From: Abby Castillo Date: Thu, 4 May 2023 16:06:22 -0700 Subject: [PATCH 16/17] finished wave 6 up to Code Coverage --- tests/test_routes.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/test_routes.py b/tests/test_routes.py index 1682bca82..bb5628b84 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -1,4 +1,4 @@ -from werkzeug.exceptions import HTTPException +#from werkzeug.exceptions import HTTPException # from app.routes import validate_book import pytest @@ -49,4 +49,17 @@ def test_get_all_planets(client, two_saved_planets): "name": "second planet", "description": "the second one", "composition": "second"} - ] \ No newline at end of file + ] + +def test_post_one_planet_returns_201(client): + # Act + response = client.post("/planets", json={ + "name": "new planet", + "description": "the new one", + "composition": "new" + }) + # response_body = response.get_json() + + # Assert + assert response.status_code == 201 + # assert response_body == "Book New Book successfully created" \ No newline at end of file From 5455d57a07ddca1cfc97fc491a1fa5ee73b833ce Mon Sep 17 00:00:00 2001 From: Aisha Date: Fri, 5 May 2023 08:03:56 -0500 Subject: [PATCH 17/17] finished wave 5 --- app/__init__.py | 4 ++-- app/models/planet.py | 20 ++++++++++++------ app/{ => routes}/routes.py | 40 +++++++++++++++++++----------------- app/routes/routes_helpers.py | 16 +++++++++++++++ seed.py | 13 ++++++++++++ tests/conftest.py | 8 ++++---- tests/test_routes.py | 6 +++--- 7 files changed, 73 insertions(+), 34 deletions(-) rename app/{ => routes}/routes.py (74%) create mode 100644 app/routes/routes_helpers.py create mode 100644 seed.py diff --git a/app/__init__.py b/app/__init__.py index 9718c19a8..c8b8fa16d 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -6,7 +6,7 @@ db = SQLAlchemy() migrate = Migrate() -load_dotenv +load_dotenv() def create_app(test_config=None): app = Flask(__name__) @@ -28,7 +28,7 @@ def create_app(test_config=None): migrate.init_app(app, db) from app.models.planet import Planet - from .routes import bp + from .routes.routes import bp app.register_blueprint(bp) return app diff --git a/app/models/planet.py b/app/models/planet.py index e1c8a2566..e880d568a 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -6,10 +6,18 @@ class Planet(db.Model): description = db.Column(db.String) composition = db.Column(db.String) + @classmethod + def from_dict(cls, data_dict): + return cls( + name=data_dict["name"], + description=data_dict["description"], + composition=data_dict["composition"] + ) + def to_dict(self): - return { - "id": self.id, - "name": self.name, - "description": self.description, - "composition": self.composition - } + return dict( + id=self.id, + name=self.name, + description=self.description, + composition=self.composition + ) \ No newline at end of file diff --git a/app/routes.py b/app/routes/routes.py similarity index 74% rename from app/routes.py rename to app/routes/routes.py index b5f1f29c1..d7048c1e4 100644 --- a/app/routes.py +++ b/app/routes/routes.py @@ -1,6 +1,7 @@ -from flask import Blueprint, jsonify, abort, make_response, request +from flask import Blueprint, jsonify, make_response, request from app.models.planet import Planet from app import db +from .routes_helpers import validate_model # planets = [ # Planet(1, "Mercury", "dark gray", "terrestrial"), @@ -13,30 +14,30 @@ bp = Blueprint("planets", __name__, url_prefix="/planets") # @bp.route("",methods=["GET"]) -# helper function -def validate_planet(planet_id): - try: - planet_id = int(planet_id) - except: - abort(make_response({"message": f"planet {planet_id} not valid"}, 400)) +# # helper function +# def validate_planet(planet_id): +# try: +# planet_id = int(planet_id) +# except: +# abort(make_response({"message": f"planet {planet_id} not valid"}, 400)) - planet = Planet.query.get(planet_id) +# planet = Planet.query.get(planet_id) - if not planet: - abort(make_response({"message": f"planet {planet_id} not found"}, 404)) +# if not planet: +# abort(make_response({"message": f"planet {planet_id} not found"}, 404)) - return planet +# return planet # routes @bp.route("/", methods=["GET"]) def get_one_planet(id): - planet = validate_planet(id) + planet = validate_model(Planet, id) return planet.to_dict(), 200 @bp.route("/", methods =["PUT"]) def update_one_planet(id): - planet = validate_planet(id) + planet = validate_model(Planet,id) request_body = request.get_json() planet.name = request_body["name"] @@ -49,7 +50,7 @@ def update_one_planet(id): @bp.route("/", methods = ["DELETE"]) def delete_one_planet(id): - planet = validate_planet(id) + planet = validate_model(Planet,id) db.session.delete(planet) db.session.commit() @@ -60,11 +61,12 @@ def delete_one_planet(id): def create_planet(): request_body=request.get_json() - new_planet = Planet( - name=request_body["name"], - description=request_body["description"], - composition=request_body["composition"] - ) + # new_planet = Planet( + # name=request_body["name"], + # description=request_body["description"], + # composition=request_body["composition"] + # ) + new_planet = Planet.from_dict(request_body) db.session.add(new_planet) db.session.commit() diff --git a/app/routes/routes_helpers.py b/app/routes/routes_helpers.py new file mode 100644 index 000000000..241ccb8bb --- /dev/null +++ b/app/routes/routes_helpers.py @@ -0,0 +1,16 @@ +from flask import abort, make_response + +# HELPER FUNCTION +def validate_model(cls, id): + try: + id = int(id) + except: + abort(make_response({"message": f"{id} was invalid"}, 400)) + + model = cls.query.get(id) + + if not model: + abort(make_response( + {"message": f"{cls.__name__} with id {id} was not found"}, 404)) + + return model \ No newline at end of file diff --git a/seed.py b/seed.py new file mode 100644 index 000000000..480cb5b94 --- /dev/null +++ b/seed.py @@ -0,0 +1,13 @@ +from app import create_app, db +from app.models.planet import Planet + +my_app = create_app() +with my_app.app_context(): + db.session.add(Planet(name="Mercury", description="dark gray", composition="terrestrial")) + db.session.add(Planet(name="Venus", description="light yellow", composition="terrestrial")) + db.session.add(Planet(name="Earth", description="blue and green", composition="terrestrial")) + db.session.add(Planet(name="Mars", description="red", composition="terrestrial")) + db.session.add(Planet(name="Jupiter", description="orange and brown", composition="gas giant")) + + db.session.commit() + diff --git a/tests/conftest.py b/tests/conftest.py index ce5d38800..3f9fdffe9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -28,11 +28,11 @@ def client(app): @pytest.fixture def two_saved_planets(app): first_planet = Planet(name="first planet", - description="the first one", - composition="first") + description="the first one", + composition="first") second_planet = Planet(name="second planet", - description="the second one", - composition="second") + description="the second one", + composition="second") db.session.add_all([first_planet, second_planet]) db.session.commit() \ No newline at end of file diff --git a/tests/test_routes.py b/tests/test_routes.py index bb5628b84..d170cc842 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -32,7 +32,7 @@ def test_get_first_planet_from_empty_database(client): # Assert assert response.status_code == 404 - assert response_body == {"message": f"planet 1 not found"} + assert response_body == {'message': 'Planet with id 1 was not found'} def test_get_all_planets(client, two_saved_planets): response = client.get("/planets") @@ -58,8 +58,8 @@ def test_post_one_planet_returns_201(client): "description": "the new one", "composition": "new" }) - # response_body = response.get_json() + response_body = response.get_data(as_text=True) # Assert assert response.status_code == 201 - # assert response_body == "Book New Book successfully created" \ No newline at end of file + assert response_body == "Planet new planet successfully created" \ No newline at end of file