diff --git a/.idea/shelf/clean_up_the_try_and_catch__to_a_if_check.xml b/.idea/shelf/clean_up_the_try_and_catch__to_a_if_check.xml new file mode 100644 index 000000000..3103b921c --- /dev/null +++ b/.idea/shelf/clean_up_the_try_and_catch__to_a_if_check.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py index 70b4cabfe..eb9cfc91b 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,7 +1,25 @@ +from importlib import import_module from flask import Flask +from .routes.planet_routes import planets_bp +from .db import db, migrate +from .models import planet +import os - -def create_app(test_config=None): +def create_app(config=None): app = Flask(__name__) + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + + if config: + app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('SQLALCHEMY_DATABASE_URI') + app.config.update(config) + else: + app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('SQLALCHEMY_DATABASE_URI') + + db.init_app(app) + migrate.init_app(app, db) + + app.register_blueprint(planets_bp) + return app + diff --git a/app/db.py b/app/db.py new file mode 100644 index 000000000..e9b3927cb --- /dev/null +++ b/app/db.py @@ -0,0 +1,7 @@ +from flask_sqlalchemy import SQLAlchemy +from flask_migrate import Migrate +from .models.base import Base + +db = SQLAlchemy(model_class=Base) +migrate = Migrate() + diff --git a/app/models/__init__py b/app/models/__init__py new file mode 100644 index 000000000..e69de29bb diff --git a/app/models/base.py b/app/models/base.py new file mode 100644 index 000000000..d4c131f33 --- /dev/null +++ b/app/models/base.py @@ -0,0 +1,5 @@ +from sqlalchemy.orm import DeclarativeBase + +class Base(DeclarativeBase): + pass + diff --git a/app/models/planet.py b/app/models/planet.py new file mode 100644 index 000000000..43e26c668 --- /dev/null +++ b/app/models/planet.py @@ -0,0 +1,48 @@ +from sqlalchemy.orm import Mapped, mapped_column +from ..db import db + +class Planet(db.Model): + __tablename__ = "planets" + id: Mapped[int] = mapped_column(primary_key= True, autoincrement=True) + name: Mapped[str] + description: Mapped[str] + moon: Mapped[int] + + def to_dict(self): + return dict( + id=self.id, + name=self.name, + description=self.description, + moon=self.moon + ) + + + + + + + +# class Planet: +# def __init__(self,id, name, description, moon): +# self.id = id +# self.name = name +# self.description = description +# self.moon = moon +# +# planets = [ +# Planet(1, "Mercury", "the smallest planet in the solar system and orbits closest to the Sun, with extreme temperatures ranging from 430°C (800°F) during the day to -180°C (-290°F) at night.", 0), +# Planet(2, "Venus", "the Sun and has a thick, toxic atmosphere composed mostly of carbon dioxide, creating a runaway greenhouse effect that makes it the hottest planet in the solar system with surface temperatures around 465°C (870°F", 0), +# Planet(3, "Earth", "Our home planet, the only known planet to harbor life",1), +# Planet(4,"Mars", "Red Planet due to its reddish appearance caused by iron oxide (rust) on its surface. It has a thin atmosphere composed mostly of carbon dioxide", 2 ), +# Planet(4, "Pluto", " filled with icy bodies and other small objects. Once considered the ninth planet in the solar system, it was reclassified as a dwarf planet in 2006 due to its size and the fact that it hasn’t cleared its orbit of other debris. Pluto has a rocky core surrounded by a mantle of water ice and a thin atmosphere of nitrogen, methane, and carbon monoxide.", 5), +# Planet(5, "Jupiter","is the largest planet in the solar system, a gas giant composed primarily of hydrogen and helium, known for its Great Red Spot—a massive storm larger than Earth", 92), +# Planet(6, "Saturn","sixth planet from the Sun and is best known for its extensive and stunning ring system, made mostly of ice and rock particles. It is a gas giant composed primarily of hydrogen and helium" , 146), +# Planet(7, "Uranus","is the seventh planet from the Sun, an ice giant with a blue-green color due to the presence of methane in its atmosphere. It is unique for rotating on its side, with an extreme axial tilt of about 98 degrees", 27 ), +# Planet(8, "Neptune", "is a blue ice giant, the eighth planet from the Sun. Known for strong winds and dark storms", 14), +# Planet(9, "Pluto", " a small, icy world in the outer solar system. It has a diverse, frozen landscape featuring a distinctive heart-shaped region", 5 ), +# ] + + + + + diff --git a/app/routes.py b/app/routes.py deleted file mode 100644 index 8e9dfe684..000000000 --- a/app/routes.py +++ /dev/null @@ -1,2 +0,0 @@ -from flask import Blueprint - diff --git a/app/routes/planet_routes.py b/app/routes/planet_routes.py new file mode 100644 index 000000000..617525d6f --- /dev/null +++ b/app/routes/planet_routes.py @@ -0,0 +1,125 @@ +from flask import Blueprint, abort, make_response, request, Response +from ..db import db +from app.models.planet import Planet + +planets_bp = Blueprint("planets_bp", __name__, url_prefix="/planets") + +@planets_bp.post("") +def create_planet(): + request_body = request.get_json() + name = request_body["name"] + moon= request_body["moon"] + description = request_body["description"] + + new_planet = Planet(name=name, moon=moon, description=description) + db.session.add(new_planet) + db.session.commit() + response = new_planet.to_dict() + return response, 201 + +@planets_bp.get("") +def get_all_planets(): + description_param = request.args.get("description") + moon_param = request.args.get("moon") + moon_op_param = request.args.get("moon_param") + sort_param = request.args.get("sort") + + query = db.select(Planet) + + if description_param: + query = query.where(Planet.description.like(f"%{description_param}%")) + + if moon_param: + try: + moon_count = int(moon_param) + # Dictionary of comparison operators + moon_operators = { + "eq": Planet.moon.__eq__, + "gt": Planet.moon.__gt__, + "lt": Planet.moon.__lt__, + "gte": Planet.moon.__ge__, + "lte": Planet.moon.__le__ + } + operator_func = moon_operators.get(moon_op_param, Planet.moon.__eq__) + if operator_func: + query = query.where(operator_func(moon_count)) + except ValueError: + return {"message": "Invalid moon parameter"}, 400 + + sort_options ={ + "name": Planet.name, + "name_desc": Planet.name.desc(), + "moon": Planet.moon, + "moon_desc": Planet.moon.desc(), + "id": Planet.id + } + + sort_field = sort_options.get(sort_param, Planet.id) + query = query.order_by(sort_field) + + planets = db.session.scalars(query).all() + planets_response = [planet.to_dict() for planet in planets] + return planets_response + +@planets_bp.get("/") +def get_one_planet(planet_id): + planet = validate_planet_one(planet_id) + + return { + "id": planet.id, + "name": planet.name, + "description": planet.description, + "moon": planet.moon + } + +@planets_bp.put("/") +def update_planet(planet_id): + planets = Planet.query.all() + planet = validate_planet(planet_id, planets) + request_body = request.get_json() + + planet.name= request_body["name"] + planet.description = request_body["description"] + planet.moon= request_body["moon"] + db.session.commit() + + return Response(status=204, mimetype="application/json") + +@planets_bp.delete("/") +def delete_planet(planet_id): + planet = validate_planet_one(planet_id) + db.session.delete(planet) + db.session.commit() + + return Response(status=204, mimetype="application/json") + +def validate_planet(planet_id, planets): + # Narrow the errors - data error, type error + try: + planet_id = int(planet_id) + except: + abort(make_response({"message": f"Planet id {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)) + + +def validate_planet_one(planet_id): + + try: + planet_id = int(planet_id) + except: + response = {"message": f"planet {planet_id} invalid"} + abort(make_response(response, 400)) + + query = db.select(Planet).where(Planet.id == planet_id) + planet = db.session.scalar(query) + + if not planet: + response = {"message": f"{planet_id} not found"} + abort(make_response(response, 404)) + + return planet \ No newline at end of file diff --git a/coworking_agreement.md b/coworking_agreement.md index 463598c27..b24cc7b91 100644 --- a/coworking_agreement.md +++ b/coworking_agreement.md @@ -1,25 +1,44 @@ -# Coworking Agreement +.# Coworking Agreement Talk through each section with your partner. Add notes on what you discussed and agreed upon in each section. At the bottom, type your names to sign off on your agreement. ## Accessibility Needs *What does each team member need access to in order to succeed and show up the best they can?* +1- Time and energy +2- Slowness +3- Communication +4- Fallibility + ## 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?* +Depends +1- pair programming +2- Independent- when we work independent we Communicate and share our changes via slack or zoom, etc. +3- tools and technologies we used to collaborate is zoom and slack. ## Learning Style *How does each team member learn best in project settings?* +1- Doing +2- Explaining +3- Researching +4- Coping ## Preferred Feedback Style *How does each team member best receive feedback?* +- By being honest and open. ## One Team Communication Skill to Improve *What is a teamwork-related skill you want to work on?* +for Salma +- Speak more +- Repeat the info to make sure that I understand correctly +for Tami +- Speck clear and slowly ## Optional: Other agreements *Other co-working agreements that were not captured in the above sections.* ## Signatures -______________ _______________ -Date: _________ +Salma Anany, Tami Gaertner +Date: oct 21,2024 diff --git a/migrations/README b/migrations/README new file mode 100644 index 000000000..0e0484415 --- /dev/null +++ b/migrations/README @@ -0,0 +1 @@ +Single-database configuration for Flask. diff --git a/migrations/alembic.ini b/migrations/alembic.ini new file mode 100644 index 000000000..ec9d45c26 --- /dev/null +++ b/migrations/alembic.ini @@ -0,0 +1,50 @@ +# 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,flask_migrate + +[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 + +[logger_flask_migrate] +level = INFO +handlers = +qualname = flask_migrate + +[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..4c9709271 --- /dev/null +++ b/migrations/env.py @@ -0,0 +1,113 @@ +import logging +from logging.config import fileConfig + +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') + + +def get_engine(): + try: + # this works with Flask-SQLAlchemy<3 and Alchemical + return current_app.extensions['migrate'].db.get_engine() + except (TypeError, AttributeError): + # this works with Flask-SQLAlchemy>=3 + return current_app.extensions['migrate'].db.engine + + +def get_engine_url(): + try: + return get_engine().url.render_as_string(hide_password=False).replace( + '%', '%%') + except AttributeError: + return str(get_engine().url).replace('%', '%%') + + +# 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', get_engine_url()) +target_db = current_app.extensions['migrate'].db + +# 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 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. + + 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=get_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.') + + conf_args = current_app.extensions['migrate'].configure_args + if conf_args.get("process_revision_directives") is None: + conf_args["process_revision_directives"] = process_revision_directives + + connectable = get_engine() + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=get_metadata(), + **conf_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/4294dced1c4c_adds_planet_model.py b/migrations/versions/4294dced1c4c_adds_planet_model.py new file mode 100644 index 000000000..9ea17816a --- /dev/null +++ b/migrations/versions/4294dced1c4c_adds_planet_model.py @@ -0,0 +1,39 @@ +"""adds Planet model + +Revision ID: 4294dced1c4c +Revises: c72d9c7a8b07 +Create Date: 2024-10-25 13:10:11.729115 + +""" +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = '4294dced1c4c' +down_revision = 'c72d9c7a8b07' +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('description', sa.String(), nullable=False), + sa.Column('moon', sa.Integer(), nullable=False), + sa.PrimaryKeyConstraint('id') + ) + op.drop_table('planets') + # ### end Alembic commands ### + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('planets', + sa.Column('id', sa.INTEGER(), sa.Identity(always=False, start=1, increment=1, minvalue=1, maxvalue=2147483647, cycle=False, cache=1), autoincrement=True, nullable=False), + sa.Column('name', sa.TEXT(), autoincrement=False, nullable=False), + sa.Column('description', sa.TEXT(), autoincrement=False, nullable=False), + sa.Column('moon', sa.INTEGER(), autoincrement=False, nullable=True), + sa.PrimaryKeyConstraint('id', name='planets_pkey') + ) + op.drop_table('planet') + # ### end Alembic commands ### diff --git a/project-directions/wave_03.md b/project-directions/wave_03.md index f4128d650..fdbe8c705 100644 --- a/project-directions/wave_03.md +++ b/project-directions/wave_03.md @@ -18,3 +18,4 @@ As a client, I want to send a request... 1. ...with new valid `planet` data and get a success response, so that I know the API saved the planet data 1. ...to get all existing `planets`, so that I can see a list of planets, with their `id`, `name`, `description`, and other data of the `planet`. + diff --git a/project-directions/wave_06.md b/project-directions/wave_06.md index 7d854f465..756a7e53e 100644 --- a/project-directions/wave_06.md +++ b/project-directions/wave_06.md @@ -8,13 +8,13 @@ Complete the following requirements, with similar functionality to the Hello Boo 1. Populate it with two environment variables: `SQLALCHEMY_DATABASE_URI` and `SQLALCHEMY_TEST_DATABASE_URI`. Set their values to the appropriate connection strings. 1. Create a test database with the correct, matching name. 1. Refactor the `create_app` method to: - * Check for a configuration flag - * Read the correct database location from the appropriate environment variables + - Check for a configuration flag + - Read the correct database location from the appropriate environment variables 1. Manually test that our development environment still works. 1. Create a `tests` folder with the files: - - `tests/__init__.py` - - `tests/conftest.py` - - `tests/test_routes.py`. + - `tests/__init__.py` + - `tests/conftest.py` + - `tests/test_routes.py`. 1. Populate `tests/conftest.py` with the recommended configuration. 1. Create a test to check `GET` `/planets` returns `200` and an empty array. 1. Confirm this test runs and passes. @@ -23,7 +23,7 @@ Complete the following requirements, with similar functionality to the Hello Boo Create test fixtures and unit tests for the following test cases: -1. `GET` `/planets/1` returns a response body that matches our fixture +1. `GET` `/planets/1` returns a response body that matches our fixture ( to get a planet, single planet) 1. `GET` `/planets/1` with no data in test database (no fixture) returns a `404` 1. `GET` `/planets` with valid test data (fixtures) returns a `200` with an array including appropriate test data 1. `POST` `/planets` with a JSON request body returns a `201` diff --git a/requirements.txt b/requirements.txt index 24c7e56f8..bd4b5d142 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,17 +1,24 @@ alembic==1.13.1 autopep8==1.5.5 -blinker==1.7 +blinker==1.7.0 certifi==2020.12.5 chardet==4.0.0 click==8.1.7 +coverage==7.6.3 +exceptiongroup==1.2.2 Flask==3.0.2 Flask-Migrate==4.0.5 Flask-SQLAlchemy==3.1.1 idna==2.10 +importlib_metadata==8.5.0 +iniconfig==2.0.0 itsdangerous==2.1.2 Jinja2==3.1.3 Mako==1.1.4 MarkupSafe==2.1.5 +packaging==24.1 +pluggy==1.5.0 +psycopg2==2.9.10 psycopg2-binary==2.9.9 pycodestyle==2.6.0 pytest==8.0.0 @@ -23,5 +30,8 @@ requests==2.25.1 six==1.15.0 SQLAlchemy==2.0.25 toml==0.10.2 +tomli==2.0.2 +typing_extensions==4.12.2 urllib3==1.26.4 -Werkzeug==3.0.1 \ No newline at end of file +Werkzeug==3.0.1 +zipp==3.20.2 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..3bc0b9de8 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,77 @@ +import pytest +from app import create_app +from app.db import db +from flask.signals import request_finished +from dotenv import load_dotenv +import os +from app.models.planet import Planet + +load_dotenv() + +@pytest.fixture +def app(): + test_config = { + "TESTING": True, + "SQLALCHEMY_DATABASE_URI": os.environ.get('SQLALCHEMY_TEST_DATABASE_URI') + } + app = create_app(test_config) + + @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 get_every_single_planet(app): + planet = [Planet(name="Coruscant", + description="City-covered planet that served as the seat of government for the Galactic Republic and Empire", + moon=4), + Planet(name="Tatooine", + description="Desert world with binary suns, home to the Skywalker family and Jabba the Hutt", + moon=3), Planet(name="Naboo", + description="Beautiful planet with rolling plains and vast seas, homeworld of Padmé Amidala", + moon=1), + Planet(name="Hoth", description="Frozen ice planet that briefly served as a Rebel Alliance base", + moon=2), + + Planet(name="Endor", + description="Forest moon home to the Ewoks and site of the second Death Star's destruction", + moon=9)] + db.session.add_all(planet) + db.session.commit() + +@pytest.fixture +def get_planet_invalid_id(app): + return "abc" + +@pytest.fixture +def two_saved_planets(app): + mercury = Planet(name = "Mecury", description = "the hotess next to the sun", moon = 0) + vulcan = Planet(name = "Vulcan", description = "the best", moon = 2) + db.session.add_all([mercury, vulcan]) + db.session.commit() + +@pytest.fixture +def add_new_planet(app): + romulus = Planet(name = "Romulus", description = "Homeworld of the Romulan Star Empire, featuring green-tinted skies and advanced architecture.", moon = 2) + db.session.add(romulus) + db.session.commit() + +@pytest.fixture +def update_existing_planet(app): + kronos= Planet(name ="Kronos", description = "Homeword of the Klingon Empire, rich in warrior culture and tradition, featuring magnificent cities built among dramatic mountain ranges, home to the legendary Great Hall of the High Council, and birthplace of many of the quadrant's greatest warriors and most honored traditions", moon = 7) + db.session.add(kronos) + 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..bc4ace3a1 --- /dev/null +++ b/tests/test_routes.py @@ -0,0 +1,96 @@ +import pytest + +def test_get_every_single_planet(client, get_every_single_planet): + response = client.get(f"/planets") + response_body = response.get_json() + + # assert + assert response.status_code == 200 + assert len(response_body) == 5 + +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_one_planet_not_found_404(client): + # Arrange + # No setup needed - we want an empty database + # Act + response = client.get(f"/planets/10") + response_body = response.get_json() + # Assert + assert response.status_code == 404 + assert response_body == {"message": "10 not found"} + +def test_get_one_planet_400(client, get_planet_invalid_id): + # Arrange + # No setup needed - we want an empty database + # Act + response = client.get(f"/planets/abc") + response_body = response.get_json() + # Assert + assert response.status_code == 400 + assert response_body == {"message": f"planet abc invalid"} + +def test_get_one_planet_success_200(client, two_saved_planets): + # Act + response = client.get(f"/planets/2") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == { + "id": 2, + "name": "Vulcan", + "description": "the best", + "moon": 2 + } + +def test_create_new_planet_with_data_201(client, add_new_planet): + # Act + response = client.post("/planets", json={ + "name": "Romulus", + "description": "Homeworld of the Romulan Star Empire, featuring green-tinted skies and advanced architecture.", + "moon": 2 + }) + response_body = response.get_json() + response_body.pop("id") + + # Assert + assert response.status_code == 201 + assert response_body == { + "name": "Romulus", + "description": "Homeworld of the Romulan Star Empire, featuring green-tinted skies and advanced architecture.", + "moon": 2 + } + +def test_update_existing_planet_minus_one_moon(client, update_existing_planet): + # Act + response = client.put("/planets/1", json={ + "name": "Kronos", + "description": "rich in warrior culture and tradition, featuring magnificent cities built among dramatic mountain ranges, home to the legendary Great Hall of the High Council, and birthplace of many of the quadrant's greatest warriors and most honored traditions", + "moon": 6 + }) + + # Assert + assert response.status_code == 204 + verify_response = client.get("planets/1") + verify_body = verify_response.get_json() + assert verify_body["moon"] == 6 + +def test_delete_existing_planet(client,add_new_planet): + # Act + response = client.delete("/planets/1") + + # Assert + assert response.status_code == 204 + check_respone = client.get("/planets/1") + assert check_respone.status_code == 404 + + + \ No newline at end of file