From 27565f25395de19b8dfafa0a74540f376a71a518 Mon Sep 17 00:00:00 2001 From: Dex the DevEx Assistant Date: Tue, 26 May 2026 12:52:02 -0700 Subject: [PATCH 1/5] Bump uvicorn and retest quickstart flow --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index e04f775..a05b509 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,4 @@ pydantic==2.13.4 pydantic-settings==2.14.1 pytest==9.0.3 python-dotenv==1.2.2 -uvicorn==0.47.0 +uvicorn==0.48.0 From 35eceb2c4bb2448da447f67acacf4b82e18fe358 Mon Sep 17 00:00:00 2001 From: Dex the DevEx Assistant Date: Tue, 26 May 2026 13:23:20 -0700 Subject: [PATCH 2/5] Fix Slack notifier workflow failure --- .github/workflows/tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fa7f26c..91d2678 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,7 +31,8 @@ jobs: python -m pytest - name: Report Status if: always() - uses: ravsamhq/notify-slack-action@v1 + continue-on-error: true + uses: ravsamhq/notify-slack-action@v2 with: status: ${{ job.status }} notify_when: "failure,warnings" From 8a81dbe5c813267683cb32e0d10c85735bfd6991 Mon Sep 17 00:00:00 2001 From: Dex the DevEx Assistant Date: Tue, 26 May 2026 13:31:46 -0700 Subject: [PATCH 3/5] Skip incomplete airport rows in list responses --- app/routers/airport.py | 12 +++++++++++- app/tests/test_airport.py | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/app/routers/airport.py b/app/routers/airport.py index 2cde684..a13219b 100644 --- a/app/routers/airport.py +++ b/app/routers/airport.py @@ -112,11 +112,21 @@ def get_airports_list( try: result = db.query(query, country=country, limit=limit, offset=offset) airports = [r for r in result] - return airports + return _filter_complete_airports(airports) except Exception as e: raise HTTPException(status_code=500, detail=f"Unexpected error: {e}") +def _filter_complete_airports(airports: list[dict]) -> list[dict]: + """Drop rows that cannot satisfy the Airport response model.""" + required_fields = ("airportname", "city", "country") + return [ + airport + for airport in airports + if all(field in airport and airport[field] is not None for field in required_fields) + ] + + class DestinationAirport(BaseModel): """Model for Destination Airport""" diff --git a/app/tests/test_airport.py b/app/tests/test_airport.py index 7ac023a..627d0f9 100644 --- a/app/tests/test_airport.py +++ b/app/tests/test_airport.py @@ -3,10 +3,29 @@ from couchbase.exceptions import DocumentNotFoundException from app.main import app +from app.routers.airport import _filter_complete_airports client = TestClient(app) +def test_filter_complete_airports_skips_incomplete_rows(): + complete_airport = { + "airportname": "Test Airport", + "city": "Test City", + "country": "Test Country", + "faa": "TAA", + } + incomplete_airport = { + "city": "Initial Test City", + "country": "Initial Test Country", + "faa": "TESTFAA", + } + + assert _filter_complete_airports([complete_airport, incomplete_airport]) == [ + complete_airport + ] + + class TestAirport: def test_add_airport( self, couchbase_client, airport_api, airport_collection, helpers From 546b1037e94f29dffcecfb3e7e5df8962b7cd53a Mon Sep 17 00:00:00 2001 From: Dex the DevEx Assistant Date: Wed, 27 May 2026 12:16:32 -0700 Subject: [PATCH 4/5] Fix airport list pagination guard --- app/routers/airport.py | 23 ++++++++-------- app/tests/test_airport.py | 55 +++++++++++++++++++++++++++------------ 2 files changed, 50 insertions(+), 28 deletions(-) diff --git a/app/routers/airport.py b/app/routers/airport.py index a13219b..ba99f03 100644 --- a/app/routers/airport.py +++ b/app/routers/airport.py @@ -79,6 +79,15 @@ def get_airports_list( db=Depends(CouchbaseClient), ) -> list[Airport]: """Get a list of airports with pagination. Optionally, filter by country.""" + completeness_filters = """ + airport.airportname IS NOT MISSING + AND airport.airportname IS NOT NULL + AND airport.city IS NOT MISSING + AND airport.city IS NOT NULL + AND airport.country IS NOT MISSING + AND airport.country IS NOT NULL + """ + if country: query = """ SELECT airport.airportname, @@ -90,6 +99,7 @@ def get_airports_list( airport.tz FROM airport AS airport WHERE airport.country = $country + AND """ + completeness_filters + """ ORDER BY airport.airportname LIMIT $limit OFFSET $offset; @@ -104,6 +114,7 @@ def get_airports_list( airport.icao, airport.tz FROM airport AS airport + WHERE """ + completeness_filters + """ ORDER BY airport.airportname LIMIT $limit OFFSET $offset; @@ -112,21 +123,11 @@ def get_airports_list( try: result = db.query(query, country=country, limit=limit, offset=offset) airports = [r for r in result] - return _filter_complete_airports(airports) + return airports except Exception as e: raise HTTPException(status_code=500, detail=f"Unexpected error: {e}") -def _filter_complete_airports(airports: list[dict]) -> list[dict]: - """Drop rows that cannot satisfy the Airport response model.""" - required_fields = ("airportname", "city", "country") - return [ - airport - for airport in airports - if all(field in airport and airport[field] is not None for field in required_fields) - ] - - class DestinationAirport(BaseModel): """Model for Destination Airport""" diff --git a/app/tests/test_airport.py b/app/tests/test_airport.py index 627d0f9..a99226b 100644 --- a/app/tests/test_airport.py +++ b/app/tests/test_airport.py @@ -3,27 +3,48 @@ from couchbase.exceptions import DocumentNotFoundException from app.main import app -from app.routers.airport import _filter_complete_airports +from app.routers.airport import get_airports_list client = TestClient(app) -def test_filter_complete_airports_skips_incomplete_rows(): - complete_airport = { - "airportname": "Test Airport", - "city": "Test City", - "country": "Test Country", - "faa": "TAA", - } - incomplete_airport = { - "city": "Initial Test City", - "country": "Initial Test Country", - "faa": "TESTFAA", - } - - assert _filter_complete_airports([complete_airport, incomplete_airport]) == [ - complete_airport - ] +class RecordingDB: + def __init__(self, rows): + self.rows = rows + self.calls = [] + + def query(self, query, **params): + self.calls.append((query, params)) + return self.rows + + +def test_list_airports_bakes_required_fields_into_the_query_before_pagination(): + db = RecordingDB([]) + + assert get_airports_list(limit=3, offset=6, db=db) == [] + + query, params = db.calls[0] + assert "airport.airportname IS NOT MISSING" in query + assert "airport.airportname IS NOT NULL" in query + assert "airport.city IS NOT MISSING" in query + assert "airport.city IS NOT NULL" in query + assert "airport.country IS NOT MISSING" in query + assert "airport.country IS NOT NULL" in query + assert "ORDER BY airport.airportname" in query + assert "LIMIT $limit" in query + assert "OFFSET $offset" in query + assert params == {"country": None, "limit": 3, "offset": 6} + + +def test_list_airports_bakes_country_filter_into_the_query_when_present(): + db = RecordingDB([]) + + assert get_airports_list(country="France", limit=2, offset=4, db=db) == [] + + query, params = db.calls[0] + assert "WHERE airport.country = $country" in query + assert "airport.airportname IS NOT MISSING" in query + assert params == {"country": "France", "limit": 2, "offset": 4} class TestAirport: From dad0c3efa712ca206e0f3b7c33429dfe26bbced6 Mon Sep 17 00:00:00 2001 From: Dex the DevEx Assistant Date: Mon, 1 Jun 2026 12:16:11 -0700 Subject: [PATCH 5/5] Drop airport list pagination guard --- app/routers/airport.py | 11 ----------- app/tests/test_airport.py | 40 --------------------------------------- 2 files changed, 51 deletions(-) diff --git a/app/routers/airport.py b/app/routers/airport.py index ba99f03..2cde684 100644 --- a/app/routers/airport.py +++ b/app/routers/airport.py @@ -79,15 +79,6 @@ def get_airports_list( db=Depends(CouchbaseClient), ) -> list[Airport]: """Get a list of airports with pagination. Optionally, filter by country.""" - completeness_filters = """ - airport.airportname IS NOT MISSING - AND airport.airportname IS NOT NULL - AND airport.city IS NOT MISSING - AND airport.city IS NOT NULL - AND airport.country IS NOT MISSING - AND airport.country IS NOT NULL - """ - if country: query = """ SELECT airport.airportname, @@ -99,7 +90,6 @@ def get_airports_list( airport.tz FROM airport AS airport WHERE airport.country = $country - AND """ + completeness_filters + """ ORDER BY airport.airportname LIMIT $limit OFFSET $offset; @@ -114,7 +104,6 @@ def get_airports_list( airport.icao, airport.tz FROM airport AS airport - WHERE """ + completeness_filters + """ ORDER BY airport.airportname LIMIT $limit OFFSET $offset; diff --git a/app/tests/test_airport.py b/app/tests/test_airport.py index a99226b..7ac023a 100644 --- a/app/tests/test_airport.py +++ b/app/tests/test_airport.py @@ -3,50 +3,10 @@ from couchbase.exceptions import DocumentNotFoundException from app.main import app -from app.routers.airport import get_airports_list client = TestClient(app) -class RecordingDB: - def __init__(self, rows): - self.rows = rows - self.calls = [] - - def query(self, query, **params): - self.calls.append((query, params)) - return self.rows - - -def test_list_airports_bakes_required_fields_into_the_query_before_pagination(): - db = RecordingDB([]) - - assert get_airports_list(limit=3, offset=6, db=db) == [] - - query, params = db.calls[0] - assert "airport.airportname IS NOT MISSING" in query - assert "airport.airportname IS NOT NULL" in query - assert "airport.city IS NOT MISSING" in query - assert "airport.city IS NOT NULL" in query - assert "airport.country IS NOT MISSING" in query - assert "airport.country IS NOT NULL" in query - assert "ORDER BY airport.airportname" in query - assert "LIMIT $limit" in query - assert "OFFSET $offset" in query - assert params == {"country": None, "limit": 3, "offset": 6} - - -def test_list_airports_bakes_country_filter_into_the_query_when_present(): - db = RecordingDB([]) - - assert get_airports_list(country="France", limit=2, offset=4, db=db) == [] - - query, params = db.calls[0] - assert "WHERE airport.country = $country" in query - assert "airport.airportname IS NOT MISSING" in query - assert params == {"country": "France", "limit": 2, "offset": 4} - - class TestAirport: def test_add_airport( self, couchbase_client, airport_api, airport_collection, helpers