From 1e0fd843795240138f6858b1b10ff41c6175982d Mon Sep 17 00:00:00 2001 From: jacob-a-brown Date: Tue, 17 Mar 2026 14:49:21 -0600 Subject: [PATCH 1/6] fix(test): encore ocotilloapi_test for bdd tests --- tests/features/environment.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/features/environment.py b/tests/features/environment.py index 9813c38f..5e1e32b9 100644 --- a/tests/features/environment.py +++ b/tests/features/environment.py @@ -17,6 +17,11 @@ import random from datetime import datetime, timedelta +# Lock test database before any db module imports +# Ensures BDD tests only use ocotilloapi_test, never ocotilloapi_dev +os.environ["POSTGRES_DB"] = "ocotilloapi_test" +os.environ["POSTGRES_PORT"] = "5432" + from alembic import command from alembic.config import Config from sqlalchemy import select From 3ad295a231abb2970276548c82bb3694d7bb178d Mon Sep 17 00:00:00 2001 From: jacob-a-brown Date: Tue, 17 Mar 2026 14:49:56 -0600 Subject: [PATCH 2/6] feat(test): print exit_code when assert fails --- tests/features/steps/cli_common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/features/steps/cli_common.py b/tests/features/steps/cli_common.py index 1483db09..03b8077a 100644 --- a/tests/features/steps/cli_common.py +++ b/tests/features/steps/cli_common.py @@ -62,7 +62,7 @@ def step_impl_command_exit_zero(context): @then("the command exits with a non-zero exit code") def step_impl_command_exit_nonzero(context): - assert context.cli_result.exit_code != 0 + assert context.cli_result.exit_code != 0, context.cli_result.exit_code # ============= EOF ============================================= From e768d8aa36717b25ae959cd49fcede04514831d0 Mon Sep 17 00:00:00 2001 From: jacob-a-brown Date: Tue, 17 Mar 2026 14:51:17 -0600 Subject: [PATCH 3/6] fix(contact): Make contact role and type non-nullable Each contact should have a role and contact_type --- ...p9c1d2e3f4a5_make_contact_role_nullable.py | 29 --------------- ...q0d1e2f3a4b5_make_contact_type_nullable.py | 35 ------------------- db/contact.py | 6 ++-- schemas/contact.py | 8 ++--- schemas/well_inventory.py | 10 ++++++ services/well_inventory_csv.py | 13 ++----- .../well-inventory-missing-contact-role.csv | 2 +- .../well-inventory-missing-contact-type.csv | 2 +- .../steps/well-inventory-csv-given.py | 1 + .../well-inventory-csv-validation-error.py | 15 +++++++- tests/features/well-inventory-csv.feature | 18 +++++----- tests/test_well_inventory.py | 8 ++--- 12 files changed, 50 insertions(+), 97 deletions(-) delete mode 100644 alembic/versions/p9c1d2e3f4a5_make_contact_role_nullable.py delete mode 100644 alembic/versions/q0d1e2f3a4b5_make_contact_type_nullable.py diff --git a/alembic/versions/p9c1d2e3f4a5_make_contact_role_nullable.py b/alembic/versions/p9c1d2e3f4a5_make_contact_role_nullable.py deleted file mode 100644 index fb53b64d..00000000 --- a/alembic/versions/p9c1d2e3f4a5_make_contact_role_nullable.py +++ /dev/null @@ -1,29 +0,0 @@ -"""make contact role nullable - -Revision ID: p9c1d2e3f4a5 -Revises: o8b9c0d1e2f3 -Create Date: 2026-03-11 10:30:00.000000 -""" - -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - -# revision identifiers, used by Alembic. -revision: str = "p9c1d2e3f4a5" -down_revision: Union[str, Sequence[str], None] = "o8b9c0d1e2f3" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - op.alter_column( - "contact", "role", existing_type=sa.String(length=100), nullable=True - ) - - -def downgrade() -> None: - op.alter_column( - "contact", "role", existing_type=sa.String(length=100), nullable=False - ) diff --git a/alembic/versions/q0d1e2f3a4b5_make_contact_type_nullable.py b/alembic/versions/q0d1e2f3a4b5_make_contact_type_nullable.py deleted file mode 100644 index 3923139e..00000000 --- a/alembic/versions/q0d1e2f3a4b5_make_contact_type_nullable.py +++ /dev/null @@ -1,35 +0,0 @@ -"""make contact type nullable - -Revision ID: q0d1e2f3a4b5 -Revises: p9c1d2e3f4a5 -Create Date: 2026-03-11 17:10:00.000000 -""" - -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa - -# revision identifiers, used by Alembic. -revision: str = "q0d1e2f3a4b5" -down_revision: Union[str, Sequence[str], None] = "p9c1d2e3f4a5" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - op.alter_column( - "contact", - "contact_type", - existing_type=sa.String(length=100), - nullable=True, - ) - - -def downgrade() -> None: - op.alter_column( - "contact", - "contact_type", - existing_type=sa.String(length=100), - nullable=False, - ) diff --git a/db/contact.py b/db/contact.py index e30b5f57..0fb59473 100644 --- a/db/contact.py +++ b/db/contact.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # =============================================================================== -from typing import List, TYPE_CHECKING, Optional +from typing import List, TYPE_CHECKING from sqlalchemy import Integer, ForeignKey, String, UniqueConstraint from sqlalchemy.ext.associationproxy import association_proxy, AssociationProxy @@ -49,8 +49,8 @@ class ThingContactAssociation(Base, AutoBaseMixin): class Contact(Base, AutoBaseMixin, ReleaseMixin, NotesMixin): name: Mapped[str] = mapped_column(String(100), nullable=True) organization: Mapped[str] = lexicon_term(nullable=True) - role: Mapped[Optional[str]] = lexicon_term(nullable=True) - contact_type: Mapped[Optional[str]] = lexicon_term(nullable=True) + role: Mapped[str] = lexicon_term(nullable=False) + contact_type: Mapped[str] = lexicon_term(nullable=False) # primary keys of the nm aquifer tables from which the contacts originate nma_pk_owners: Mapped[str] = mapped_column(String(100), nullable=True) diff --git a/schemas/contact.py b/schemas/contact.py index 29eaad45..d6fe28a0 100644 --- a/schemas/contact.py +++ b/schemas/contact.py @@ -150,8 +150,8 @@ class CreateContact(BaseCreateModel, ValidateContact): thing_id: int name: str | None = None organization: str | None = None - role: Role | None = None - contact_type: ContactType | None = None + role: Role + contact_type: ContactType nma_pk_owners: str | None = None # description: str | None = None # email: str | None = None @@ -218,8 +218,8 @@ class ContactResponse(BaseResponseModel): name: str | None organization: str | None - role: Role | None - contact_type: ContactType | None + role: Role + contact_type: ContactType incomplete_nma_phones: List[str] = [] emails: List[EmailResponse] = [] phones: List[PhoneResponse] = [] diff --git a/schemas/well_inventory.py b/schemas/well_inventory.py index 75d3edc3..05544629 100644 --- a/schemas/well_inventory.py +++ b/schemas/well_inventory.py @@ -375,6 +375,8 @@ def validate_model(self): key = f"contact_{jdx}" name = getattr(self, f"{key}_name") organization = getattr(self, f"{key}_organization") + role = getattr(self, f"{key}_role") + contact_type = getattr(self, f"{key}_type") # Treat name or organization as contact data too, so bare contacts # still go through the same cross-field rules as fully populated ones. @@ -399,6 +401,14 @@ def validate_model(self): raise ValueError( f"At least one of {key}_name or {key}_organization must be provided" ) + if not role: + raise ValueError( + f"{key}_role is required when contact data is provided" + ) + if not contact_type: + raise ValueError( + f"{key}_type is required when contact data is provided" + ) for idx in (1, 2): if any(getattr(self, f"{key}_address_{idx}_{a}") for a in all_attrs): if not all( diff --git a/services/well_inventory_csv.py b/services/well_inventory_csv.py index a2ca44f0..2d7918c1 100644 --- a/services/well_inventory_csv.py +++ b/services/well_inventory_csv.py @@ -353,21 +353,12 @@ def _make_contact(model: WellInventoryRow, well: Thing, idx) -> dict: "address_type": address_type, } ) - return { "thing_id": well.id, "name": name, "organization": organization, - "role": ( - getattr(model, f"contact_{idx}_role").value - if hasattr(getattr(model, f"contact_{idx}_role"), "value") - else getattr(model, f"contact_{idx}_role") - ), - "contact_type": ( - getattr(model, f"contact_{idx}_type").value - if hasattr(getattr(model, f"contact_{idx}_type"), "value") - else getattr(model, f"contact_{idx}_type") - ), + "role": getattr(model, f"contact_{idx}_role"), + "contact_type": getattr(model, f"contact_{idx}_type"), "emails": emails, "phones": phones, "addresses": addresses, diff --git a/tests/features/data/well-inventory-missing-contact-role.csv b/tests/features/data/well-inventory-missing-contact-role.csv index e5948aa9..a053650d 100644 --- a/tests/features/data/well-inventory-missing-contact-role.csv +++ b/tests/features/data/well-inventory-missing-contact-role.csv @@ -1,3 +1,3 @@ project,well_name_point_id,site_name,date_time,field_staff,utm_easting,utm_northing,utm_zone,elevation_ft,elevation_method,measuring_point_height_ft,field_staff_2,field_staff_3,contact_1_name,contact_1_organization,contact_1_role,contact_1_type,contact_1_phone_1,contact_1_phone_1_type,contact_1_phone_2,contact_1_phone_2_type,contact_1_email_1,contact_1_email_1_type,contact_1_email_2,contact_1_email_2_type,contact_1_address_1_line_1,contact_1_address_1_line_2,contact_1_address_1_type,contact_1_address_1_state,contact_1_address_1_city,contact_1_address_1_postal_code,contact_1_address_2_line_1,contact_1_address_2_line_2,contact_1_address_2_type,contact_1_address_2_state,contact_1_address_2_city,contact_1_address_2_postal_code,contact_2_name,contact_2_organization,contact_2_role,contact_2_type,contact_2_phone_1,contact_2_phone_1_type,contact_2_phone_2,contact_2_phone_2_type,contact_2_email_1,contact_2_email_1_type,contact_2_email_2,contact_2_email_2_type,contact_2_address_1_line_1,contact_2_address_1_line_2,contact_2_address_1_type,contact_2_address_1_state,contact_2_address_1_city,contact_2_address_1_postal_code,contact_2_address_2_line_1,contact_2_address_2_line_2,contact_2_address_2_type,contact_2_address_2_state,contact_2_address_2_city,contact_2_address_2_postal_code,directions_to_site,specific_location_of_well,repeat_measurement_permission,sampling_permission,datalogger_installation_permission,public_availability_acknowledgement,result_communication_preference,contact_special_requests_notes,ose_well_record_id,date_drilled,completion_source,total_well_depth_ft,historic_depth_to_water_ft,depth_source,well_pump_type,well_pump_depth_ft,is_open,datalogger_possible,casing_diameter_ft,measuring_point_description,well_purpose,well_purpose_2,well_status,monitoring_frequency,sampling_scenario_notes,well_measuring_notes,sample_possible -Middle Rio Grande Groundwater Monitoring,MRG-001_MP1,Smith Farm Domestic Well,2025-02-15T10:30:00,A Lopez,250000,4000000,13N,5250,Survey-grade GPS,1.5,B Chen,,John Smith,NMBGMR,,Primary,505-555-0101,Primary,,,john.smith@example.com,Primary,,,123 County Rd 7,,Mailing,NM,Los Lunas,87031,,,,,,,Maria Garcia,NMBGMR,Principal Investigator,Secondary,505-555-0123,Home,,,maria.garcia@mrgcd.nm.gov,Work,,,1931 2nd St SW,Suite 200,Mailing,NM,Albuquerque,87102,,,,,,,Gate off County Rd 7 0.4 miles south of canal crossing,Domestic well in pump house east of residence,True,True,True,True,email,Call before visits during irrigation season,OSE-123456,2010-06-15,Interpreted fr geophys logs by source agency,280,45,"Memory of owner, operator, driller",Submersible,200,True,True,0.5,Top of steel casing inside pump house marked with orange paint,Domestic,,"Active, pumping well",Biannual,Sample only when pump has been off more than 12 hours,Measure before owner starts irrigation,True +Middle Rio Grande Groundwater Monitoring,MRG-001_MP1,Smith Farm Domestic Well,2025-02-15T10:30:00,A Lopez,250000,4000000,13N,5250,Survey-grade GPS,1.5,B Chen,,John Smith No Role,NMBGMR,,Primary,505-555-0101,Primary,,,john.smith@example.com,Primary,,,123 County Rd 7,,Mailing,NM,Los Lunas,87031,,,,,,,Maria Garcia,NMBGMR,Principal Investigator,Secondary,505-555-0123,Home,,,maria.garcia@mrgcd.nm.gov,Work,,,1931 2nd St SW,Suite 200,Mailing,NM,Albuquerque,87102,,,,,,,Gate off County Rd 7 0.4 miles south of canal crossing,Domestic well in pump house east of residence,True,True,True,True,email,Call before visits during irrigation season,OSE-123456,2010-06-15,Interpreted fr geophys logs by source agency,280,45,"Memory of owner, operator, driller",Submersible,200,True,True,0.5,Top of steel casing inside pump house marked with orange paint,Domestic,,"Active, pumping well",Biannual,Sample only when pump has been off more than 12 hours,Measure before owner starts irrigation,True Middle Rio Grande Groundwater Monitoring,MRG-003_MP1,Old Orchard Well,2025-01-20T09:00:00,B Chen,250000,4000000,13N,5320,Global positioning system (GPS),1.8,,,David Emily,NMBGMR,Biologist,Primary,505-555-0303,Work,,,emily.davis@example.org,Work,,,78 Orchard Ln,,Mailing,NM,Los Lunas,87031,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,From Main St turn east on Orchard Ln well house at dead end,Abandoned irrigation well in small cinderblock building,False,False,False,True,phone,Owner prefers weekday visits,,1965-04-10,From driller's log or well report,350,60,"Reported by person other than driller owner agency",Jet,280,False,False,0.75,Top of steel casing under removable hatch use fixed reference mark,Irrigation,,Abandoned,Annual,Sampling not permitted water level only when owner present,Well house can be locked coordinate ahead,False diff --git a/tests/features/data/well-inventory-missing-contact-type.csv b/tests/features/data/well-inventory-missing-contact-type.csv index 6fd4cddc..d3b41faa 100644 --- a/tests/features/data/well-inventory-missing-contact-type.csv +++ b/tests/features/data/well-inventory-missing-contact-type.csv @@ -1,3 +1,3 @@ project,well_name_point_id,site_name,date_time,field_staff,utm_easting,utm_northing,utm_zone,elevation_ft,elevation_method,measuring_point_height_ft,field_staff_2,field_staff_3,contact_1_name,contact_1_organization,contact_1_role,contact_1_type,contact_1_phone_1,contact_1_phone_1_type,contact_1_phone_2,contact_1_phone_2_type,contact_1_email_1,contact_1_email_1_type,contact_1_email_2,contact_1_email_2_type,contact_1_address_1_line_1,contact_1_address_1_line_2,contact_1_address_1_type,contact_1_address_1_state,contact_1_address_1_city,contact_1_address_1_postal_code,contact_1_address_2_line_1,contact_1_address_2_line_2,contact_1_address_2_type,contact_1_address_2_state,contact_1_address_2_city,contact_1_address_2_postal_code,contact_2_name,contact_2_organization,contact_2_role,contact_2_type,contact_2_phone_1,contact_2_phone_1_type,contact_2_phone_2,contact_2_phone_2_type,contact_2_email_1,contact_2_email_1_type,contact_2_email_2,contact_2_email_2_type,contact_2_address_1_line_1,contact_2_address_1_line_2,contact_2_address_1_type,contact_2_address_1_state,contact_2_address_1_city,contact_2_address_1_postal_code,contact_2_address_2_line_1,contact_2_address_2_line_2,contact_2_address_2_type,contact_2_address_2_state,contact_2_address_2_city,contact_2_address_2_postal_code,directions_to_site,specific_location_of_well,repeat_measurement_permission,sampling_permission,datalogger_installation_permission,public_availability_acknowledgement,result_communication_preference,contact_special_requests_notes,ose_well_record_id,date_drilled,completion_source,total_well_depth_ft,historic_depth_to_water_ft,depth_source,well_pump_type,well_pump_depth_ft,is_open,datalogger_possible,casing_diameter_ft,measuring_point_description,well_purpose,well_purpose_2,well_status,monitoring_frequency,sampling_scenario_notes,well_measuring_notes,sample_possible -Middle Rio Grande Groundwater Monitoring,MRG-001_MP1,Smith Farm Domestic Well,2025-02-15T10:30:00,A Lopez,250000,4000000,13N,5250,Survey-grade GPS,1.5,B Chen,,John Smith,NMBGMR,Owner,,505-555-0101,Primary,,,john.smith@example.com,Primary,,,123 County Rd 7,,Mailing,NM,Los Lunas,87031,,,,,,,Maria Garcia,NMBGMR,Principal Investigator,Secondary,505-555-0123,Home,,,maria.garcia@mrgcd.nm.gov,Work,,,1931 2nd St SW,Suite 200,Mailing,NM,Albuquerque,87102,,,,,,,Gate off County Rd 7 0.4 miles south of canal crossing,Domestic well in pump house east of residence,True,True,True,True,email,Call before visits during irrigation season,OSE-123456,2010-06-15,From driller's log or well report,280,45,"Memory of owner, operator, driller",submersible,200,True,True,0.5,Top of steel casing inside pump house marked with orange paint,Domestic,,"Active, pumping well",Biannual,Sample only when pump has been off more than 12 hours,Measure before owner starts irrigation,True +Middle Rio Grande Groundwater Monitoring,MRG-001_MP1,Smith Farm Domestic Well,2025-02-15T10:30:00,A Lopez,250000,4000000,13N,5250,Survey-grade GPS,1.5,B Chen,,John Smith No Type,NMBGMR,Owner,,505-555-0101,Primary,,,john.smith@example.com,Primary,,,123 County Rd 7,,Mailing,NM,Los Lunas,87031,,,,,,,Maria Garcia,NMBGMR,Principal Investigator,Secondary,505-555-0123,Home,,,maria.garcia@mrgcd.nm.gov,Work,,,1931 2nd St SW,Suite 200,Mailing,NM,Albuquerque,87102,,,,,,,Gate off County Rd 7 0.4 miles south of canal crossing,Domestic well in pump house east of residence,True,True,True,True,email,Call before visits during irrigation season,OSE-123456,2010-06-15,From driller's log or well report,280,45,"Memory of owner, operator, driller",submersible,200,True,True,0.5,Top of steel casing inside pump house marked with orange paint,Domestic,,"Active, pumping well",Biannual,Sample only when pump has been off more than 12 hours,Measure before owner starts irrigation,True Middle Rio Grande Groundwater Monitoring,MRG-003_MP1,Old Orchard Well,2025-01-20T09:00:00,B Chen,250000,4000000,13N,5320,Global positioning system (GPS),1.8,,,Emily Davis,NMBGMR,Biologist,Primary,505-555-0303,Work,,,emily.davis@example.org,Work,,,78 Orchard Ln,,Mailing,NM,Los Lunas,87031,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,From Main St turn east on Orchard Ln well house at dead end,Abandoned irrigation well in small cinderblock building,False,False,False,True,phone,Owner prefers weekday visits,,1965-04-10,From driller's log or well report,350,60,"From driller's log or well report",Line Shaft,280,False,False,0.75,Top of steel casing under removable hatch use fixed reference mark,Irrigation,,Abandoned,Annual,Sampling not permitted water level only when owner present,Well house can be locked coordinate ahead,False diff --git a/tests/features/steps/well-inventory-csv-given.py b/tests/features/steps/well-inventory-csv-given.py index fd302e20..8d2c6d4e 100644 --- a/tests/features/steps/well-inventory-csv-given.py +++ b/tests/features/steps/well-inventory-csv-given.py @@ -29,6 +29,7 @@ def _set_file_content(context: Context, name): def _set_file_content_from_path(context: Context, path: Path, name: str | None = None): context.file_path = path + print(context.file_path) import hashlib context.file_name = name or path.name diff --git a/tests/features/steps/well-inventory-csv-validation-error.py b/tests/features/steps/well-inventory-csv-validation-error.py index 6714acb3..543d9879 100644 --- a/tests/features/steps/well-inventory-csv-validation-error.py +++ b/tests/features/steps/well-inventory-csv-validation-error.py @@ -186,6 +186,19 @@ def step_then_the_response_includes_a_validation_error_indicating_the_invalid_em _handle_validation_error(context, expected_errors) +@then( + 'the response includes a validation error indicating the missing "contact_role" value' +) +def step_step_step_8(context): + expected_errors = [ + { + "field": "composite field error", + "error": "Value error, contact_1_role is required when contact data is provided", + } + ] + _handle_validation_error(context, expected_errors) + + @then( 'the response includes a validation error indicating the missing "contact_type" value' ) @@ -193,7 +206,7 @@ def step_step_step_8(context): expected_errors = [ { "field": "composite field error", - "error": "Value error, contact_1_type is required when contact fields are provided", + "error": "Value error, contact_1_type is required when contact data is provided", } ] _handle_validation_error(context, expected_errors) diff --git a/tests/features/well-inventory-csv.feature b/tests/features/well-inventory-csv.feature index 8a1b67ef..ee094ef2 100644 --- a/tests/features/well-inventory-csv.feature +++ b/tests/features/well-inventory-csv.feature @@ -223,19 +223,21 @@ Feature: Bulk upload well inventory from CSV via CLI And the response includes a validation error indicating the invalid email format And 1 well is imported - @positive @validation @BDMS-TBD - Scenario: Upload succeeds when a row has a contact without a contact_role + @negative @validation @BDMS-TBD + Scenario: Upload fails when a row has a contact without a "contact_role" Given my CSV file contains a row with a contact but is missing the required "contact_role" field for that contact When I run the well inventory bulk upload command - Then the command exits with code 0 - And all wells are imported + Then the command exits with a non-zero exit code + And the response includes a validation error indicating the missing "contact_role" value + And 1 well is imported - @positive @validation @BDMS-TBD - Scenario: Upload succeeds when a row has a contact without a "contact_type" + @negative @validation @BDMS-TBD + Scenario: Upload fails when a row has a contact without a "contact_type" Given my CSV file contains a row with a contact but is missing the required "contact_type" field for that contact When I run the well inventory bulk upload command - Then the command exits with code 0 - And all wells are imported + Then the command exits with a non-zero exit code + And the response includes a validation error indicating the missing "contact_type" value + And 1 well is imported @negative @validation @BDMS-TBD Scenario: Upload fails when a row has a contact with an invalid "contact_type" diff --git a/tests/test_well_inventory.py b/tests/test_well_inventory.py index dd7ccdcc..9c13d734 100644 --- a/tests/test_well_inventory.py +++ b/tests/test_well_inventory.py @@ -641,18 +641,18 @@ def test_upload_invalid_boolean_value(self): assert result.exit_code == 1 def test_upload_missing_contact_type(self): - """Upload succeeds when contact is provided without contact_type.""" + """Upload fails when contact is provided without contact_type.""" file_path = Path("tests/features/data/well-inventory-missing-contact-type.csv") if file_path.exists(): result = well_inventory_csv(file_path) - assert result.exit_code == 0 + assert result.exit_code == 1 def test_upload_missing_contact_role(self): - """Upload succeeds when contact is provided without role.""" + """Upload fails when contact is provided without role.""" file_path = Path("tests/features/data/well-inventory-missing-contact-role.csv") if file_path.exists(): result = well_inventory_csv(file_path) - assert result.exit_code == 0 + assert result.exit_code == 1 def test_upload_partial_water_level_fields(self): """Upload fails when only some water level fields are provided.""" From a0ea88d8c355113d445f224d497be1caf18d1ef7 Mon Sep 17 00:00:00 2001 From: jacob-a-brown Date: Tue, 17 Mar 2026 14:55:07 -0600 Subject: [PATCH 4/6] fix(test): remove print debugging statement --- tests/features/steps/well-inventory-csv-given.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/features/steps/well-inventory-csv-given.py b/tests/features/steps/well-inventory-csv-given.py index 8d2c6d4e..fd302e20 100644 --- a/tests/features/steps/well-inventory-csv-given.py +++ b/tests/features/steps/well-inventory-csv-given.py @@ -29,7 +29,6 @@ def _set_file_content(context: Context, name): def _set_file_content_from_path(context: Context, path: Path, name: str | None = None): context.file_path = path - print(context.file_path) import hashlib context.file_name = name or path.name From 0a306766b06490e34e154aec4601dad17418fc11 Mon Sep 17 00:00:00 2001 From: jacob-a-brown Date: Tue, 17 Mar 2026 15:06:42 -0600 Subject: [PATCH 5/6] fix(well inventory): extract role/contact_type from enum --- services/well_inventory_csv.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/well_inventory_csv.py b/services/well_inventory_csv.py index 2d7918c1..1eb2bac2 100644 --- a/services/well_inventory_csv.py +++ b/services/well_inventory_csv.py @@ -357,8 +357,8 @@ def _make_contact(model: WellInventoryRow, well: Thing, idx) -> dict: "thing_id": well.id, "name": name, "organization": organization, - "role": getattr(model, f"contact_{idx}_role"), - "contact_type": getattr(model, f"contact_{idx}_type"), + "role": getattr(model, f"contact_{idx}_role").value, + "contact_type": getattr(model, f"contact_{idx}_type").value, "emails": emails, "phones": phones, "addresses": addresses, From 0fada745287ef767646d69856417585ba7cb4cf0 Mon Sep 17 00:00:00 2001 From: jacob-a-brown Date: Tue, 17 Mar 2026 15:10:41 -0600 Subject: [PATCH 6/6] fix(test): ensure different step test names --- tests/features/steps/well-inventory-csv-validation-error.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/features/steps/well-inventory-csv-validation-error.py b/tests/features/steps/well-inventory-csv-validation-error.py index 543d9879..492af59c 100644 --- a/tests/features/steps/well-inventory-csv-validation-error.py +++ b/tests/features/steps/well-inventory-csv-validation-error.py @@ -202,7 +202,7 @@ def step_step_step_8(context): @then( 'the response includes a validation error indicating the missing "contact_type" value' ) -def step_step_step_8(context): +def step_step_step_9(context): expected_errors = [ { "field": "composite field error",