C22, Alejandra and Maybellene, part 1#1
Conversation
anselrognlie
left a comment
There was a problem hiding this comment.
You're off to a good start. All the Flask-specific code is on the right on track. There are just a few general Python points to review.
app/models/planet.py
Outdated
| @@ -0,0 +1,20 @@ | |||
| class Planet: | |||
| def __init__(self, id, name, description, size_dia_km): | |||
There was a problem hiding this comment.
👍 Great idea to include more specifics about what "size" means (the diameter in kilometers). This is often useful to do with a data value that's otherwise just a number.
app/models/planet.py
Outdated
| self.id = id | ||
| self.name = name | ||
| self.description = description | ||
| self.size = size_dia_km |
There was a problem hiding this comment.
Consider carrying the additional detail in the name of the attribute itself.
| self.description = description | ||
| self.size = size_dia_km | ||
|
|
||
| def to_dict(self): |
There was a problem hiding this comment.
👍 Nice job incorporating this refactor from the live code.
app/models/planet.py
Outdated
| return dict( | ||
| id=self.id, | ||
| name=self.name, | ||
| desc=self.description, |
There was a problem hiding this comment.
Unless there's a strong need to, resist the temptation to shorten the name in the dictionary-ified version.
app/models/planet.py
Outdated
| planets = [ | ||
| Planet(1,"some_planet", "rocky, no signs of life", 100), | ||
| Planet(2, "Earth", "with lifeforms, water and land", 5000), | ||
| Planet(3, "Pluto", "still a planet", 200) |
app/routes/planet_routes.py
Outdated
| from app.models.planet import planets | ||
|
|
||
| # created blueprint | ||
| planets_bp = Blueprint("planets_bp",__name__, url_prefix=("/planets")) |
There was a problem hiding this comment.
There's no need to wrap the url_prefix value in ().
Be sure to include a space after ,
planets_bp = Blueprint("planets_bp", __name__, url_prefix="/planets")
app/routes/planet_routes.py
Outdated
| results_list = [] | ||
|
|
||
| for planet in planets: | ||
| results_list.append(planet.to_dict()) |
There was a problem hiding this comment.
There's a great opportunity to try to use a list comprehension here.
results_list = [planet.to_dict() for planet in planets]
app/routes/planet_routes.py
Outdated
| planet_id = int(planet_id) | ||
| except ValueError: | ||
| abort(make_response({"message": f"planet {planet_id} is an invalid ID"}, 400)) | ||
| for planet in planets: |
There was a problem hiding this comment.
Consider adding a blank line between this line and the previous to help separate these two sections of code that focus on two different things.
app/routes/planet_routes.py
Outdated
| else: | ||
| abort(make_response({"message": f"planet {planet_id} not found"}, 404)) No newline at end of file |
There was a problem hiding this comment.
Python does support else blocks on loops, but as a syntax pattern that's relatively uncommon, I generally avoid it. It's also not necessary here. An else block is run if a loop runs all the way to completion. Since the only way the loop wouldn't run to completion is by finding (and returning) the desired planet, the only way we can reach this code at all is if the loop runs to completion.
We can simplify this by removing the else: an unindenting its block.
anselrognlie
left a comment
There was a problem hiding this comment.
Nice work making the modifications to connect your API to your database, expanding the endpoints, and adding some tests. Make sure you're committing any additional migrations (it looks like you update the planet model, but the migration still represents an older schema). Otherwise, everything here should be able to be applied to your task list implementations.
|
|
||
|
|
||
| def create_app(test_config=None): | ||
| def create_app(config=None): |
There was a problem hiding this comment.
👍 Thanks for renaming this. This param could be used for scenarios other than testing (the name was left over from the previous curriculum).
| from flask import Flask | ||
| from .routes.planet_routes import planets_bp | ||
| from .db import db, migrate | ||
| from .models import planet |
There was a problem hiding this comment.
Note that once we have the Planet model imported in the routes, and the routes are imported here, we don't technically need to import the planet module here. If you find the fact that VS Code shows this as not being used, it would now be safe to remove.
| # registered the planets blueprint with the app | ||
|
|
||
| app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False | ||
| app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('SQLALCHEMY_DATABASE_URI') |
There was a problem hiding this comment.
👍 Loads the connection string from the environment (provided with our .env during development).
| from sqlalchemy.orm import Mapped, mapped_column | ||
| from ..db import db | ||
|
|
||
| class Planet(db.Model): |
There was a problem hiding this comment.
👍 Nice modifications to associate this model type with our database.
| def create_planet(): | ||
| request_body = request.get_json() | ||
| name = request_body["name"] | ||
| description= request_body["description"] |
There was a problem hiding this comment.
Nit: Make sure to include spaces around assignments
description = request_body["description"]|
|
||
|
|
||
| @pytest.fixture | ||
| def three_saved_planets(app): |
There was a problem hiding this comment.
👍 Nice test fixture adding three records.
| planet3 = Planet(name="Pluto", description="still a planet", size_dia_km=200) | ||
|
|
||
| db.session.add_all([planet1, planet2, planet3]) | ||
| db.session.commit() No newline at end of file |
There was a problem hiding this comment.
Consider returning the list of records. The return value becomes the value passed in for the fixture in a test. By returning the records, we could use their ids in the dependent tests. While our approach of dropping and recreating the database for each test should guarantee that these records are ids 1, 2, and 3, we could use the ids actually assigned by the database to remove that assumption.
|
|
||
|
|
||
| def test_get_single_planet(client, three_saved_planets): | ||
| response = client.get("/planets/1") |
There was a problem hiding this comment.
If we returned the record list from the fixture, then we could write this line as
response = client.get(f"/planets/{three_saved_planets[0].id}")|
|
||
| assert response.status_code == 200 | ||
| assert response_body == { | ||
| "id": 1, |
There was a problem hiding this comment.
If we returned the record list from the fixture, then we could check the id as
"id": three_saved_planets[0].id,| response = client.get("/planets/1") | ||
| response_body = response.get_json() | ||
|
|
||
| assert response.status_code == 404 |
There was a problem hiding this comment.
👀 Be sure to check that the expected response body is also returned.
No description provided.