Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions api/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ===============================================================================
from fastapi import APIRouter
from fastapi import Query, Response
from fastapi_pagination.ext.sqlalchemy import paginate
from sqlalchemy import select, func
from starlette import status

from api.pagination import CustomPage
from constants import SRID_WGS84
from core.constants import SRID_WGS84
from core.dependencies import (
session_dependency,
admin_dependency,
Expand All @@ -27,12 +29,10 @@
)
from db.location import Location
from schemas.location import CreateLocation, LocationResponse, UpdateLocation
from services.geospatial_helper import make_within_wkt
from services.query_helper import make_query, order_sort_filter, simple_get_by_id
from services.crud_helper import model_patcher, model_deleter, model_adder
from services.geospatial_helper import make_within_wkt
from services.location_helper import set_geographic_attributes

from fastapi import APIRouter
from services.query_helper import make_query, order_sort_filter, simple_get_by_id

router = APIRouter(prefix="/location", tags=["location"])

Expand Down
15 changes: 12 additions & 3 deletions cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,19 @@ def well_inventory_csv(file_path: str):
well_inventory_csv(file_path)


@cli.command()
@click.argument(
@cli.group()
def water_levels():
"""Water-level utilities"""
pass


@water_levels.command("bulk-upload")
@click.option(
"--file",
"file_path",
type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True),
required=True,
help="Path to CSV file containing water level rows",
)
@click.option(
"--output",
Expand All @@ -71,7 +80,7 @@ def well_inventory_csv(file_path: str):
default=None,
help="Optional output format",
)
def water_levels_csv(file_path: str, output_format: str | None):
def water_levels_bulk_upload(file_path: str, output_format: str | None):
"""
parse and upload a csv
"""
Expand Down
1 change: 0 additions & 1 deletion cli/service_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ def water_levels_csv(source_file: Path | str, *, pretty_json: bool = False):
source_file = Path(source_file)

result = bulk_upload_water_levels(source_file, pretty_json=pretty_json)
print(result.stdout)
if result.stderr:
print(result.stderr, file=sys.stderr)
return result.exit_code
Expand Down
File renamed without changes.
7 changes: 3 additions & 4 deletions db/aquifer_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@

from typing import List, TYPE_CHECKING

from geoalchemy2 import Geometry
from sqlalchemy import Text, Index
from sqlalchemy.orm import relationship, Mapped, mapped_column
from sqlalchemy.ext.associationproxy import association_proxy, AssociationProxy
from geoalchemy2 import Geometry
from sqlalchemy.orm import relationship, Mapped, mapped_column

from core.constants import SRID_WGS84
from db.base import Base, AutoBaseMixin, ReleaseMixin
from db.lexicon import lexicon_term

from constants import SRID_WGS84

if TYPE_CHECKING:
from db.thing import WellScreen, ThingAquiferAssociation, Thing
from db.aquifer_type import AquiferType
Expand Down
7 changes: 3 additions & 4 deletions db/geologic_formation.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@

from typing import List, TYPE_CHECKING

from geoalchemy2 import Geometry
from sqlalchemy import Text, Index
from sqlalchemy.orm import relationship, Mapped, mapped_column
from sqlalchemy.ext.associationproxy import association_proxy, AssociationProxy
from geoalchemy2 import Geometry
from sqlalchemy.orm import relationship, Mapped, mapped_column

from core.constants import SRID_WGS84
from db.base import Base, AutoBaseMixin, ReleaseMixin
from db.lexicon import lexicon_term

from constants import SRID_WGS84

if TYPE_CHECKING:
from db.thing import Thing, WellScreen
from db.thing_geologic_formation_association import (
Expand Down
4 changes: 2 additions & 2 deletions db/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@

from geoalchemy2 import Geometry, WKBElement
from sqlalchemy import String, Integer, ForeignKey
from sqlalchemy.ext.associationproxy import association_proxy, AssociationProxy
from sqlalchemy.orm import relationship, Mapped
from sqlalchemy.testing.schema import mapped_column
from sqlalchemy.ext.associationproxy import association_proxy, AssociationProxy

from constants import SRID_WGS84
from core.constants import SRID_WGS84
from db.base import Base, AutoBaseMixin, ReleaseMixin, lexicon_term

if TYPE_CHECKING:
Expand Down
2 changes: 1 addition & 1 deletion db/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from sqlalchemy.ext.associationproxy import association_proxy, AssociationProxy
from sqlalchemy.orm import relationship, Mapped, mapped_column

from constants import SRID_WGS84
from core.constants import SRID_WGS84
from db.base import Base, AutoBaseMixin, ReleaseMixin
from db.data_provenance import DataProvenanceMixin
from db.notes import NotesMixin
Expand Down
6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ dependencies = [
"yarl==1.20.1",
]

[tool.uv]
package = true

[tool.setuptools]
packages = ["alembic", "cli", "core", "db", "schemas", "services"]

[project.scripts]
oco = "cli.cli:cli"

Expand Down
6 changes: 3 additions & 3 deletions schemas/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@
# limitations under the License.
# ===============================================================================
from datetime import date
from typing import Any
from typing import List

from geoalchemy2 import WKBElement
from geoalchemy2.shape import to_shape
from pydantic import BaseModel, model_validator, field_validator, Field, ConfigDict
from typing import Any

from constants import SRID_WGS84, SRID_UTM_ZONE_13N
from core.constants import SRID_WGS84, SRID_UTM_ZONE_13N
from core.enums import ElevationMethod, CoordinateMethod
from schemas import BaseCreateModel, BaseUpdateModel, BaseResponseModel
from schemas.notes import NoteResponse, CreateNote, UpdateNote
from services.validation.geospatial import validate_wkt_geometry
from services.util import convert_m_to_ft, transform_srid
from services.validation.geospatial import validate_wkt_geometry


# -------- VALIDATE --------
Expand Down
16 changes: 8 additions & 8 deletions services/geospatial_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@
# limitations under the License.
# ===============================================================================
import shapefile
from shapely.errors import GEOSException
from shapely.io import from_geojson

import constants
from db.thing import Thing
from db.group import GroupThingAssociation, Group
from db.location import Location, LocationThingAssociation
from geoalchemy2.functions import ST_GeomFromText, ST_Within, ST_AsGeoJSON
from geoalchemy2.shape import to_shape
from shapely.errors import GEOSException
from shapely.io import from_geojson
from shapely.wkt import loads as wkt_loads
from sqlalchemy import Select, select
from sqlalchemy.orm import aliased
from sqlalchemy import func
from sqlalchemy.orm import aliased

from core import constants
from db.group import GroupThingAssociation, Group
from db.location import Location, LocationThingAssociation
from db.thing import Thing


def get_thing_features(
Expand Down
2 changes: 1 addition & 1 deletion services/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from shapely.ops import transform
from sqlalchemy.orm import DeclarativeBase

from constants import SRID_WGS84
from core.constants import SRID_WGS84

TRANSFORMERS = {}
METERS_TO_FEET = 3.28084
Expand Down
3 changes: 3 additions & 0 deletions tests/features/data/water-levels.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
field_staff,well_name_point_id,field_event_date_time,measurement_date_time,sampler,sample_method,mp_height,level_status,depth_to_water_ft,data_quality,water_level_notes
Alice Lopez,AR0001,2025-02-15T08:00:00-07:00,2025-02-15T10:30:00-07:00,Groundwater Team,electric tape,1.5,stable,45.2,approved,Initial measurement after irrigation shutdown
Bernardo Chen,AR0002,2025-03-05T09:15:00-07:00,2025-03-05T11:10:00-07:00,Consultant,steel tape,1.8,rising,47.0,provisional,Follow-up visit; pump was off for 24h
22 changes: 17 additions & 5 deletions tests/features/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
ThingGeologicFormationAssociation,
Base,
Asset,
Sample,
)
from db.engine import session_ctx

Expand Down Expand Up @@ -687,12 +688,16 @@ def before_all(context):

def after_all(context):
with session_ctx() as session:
for table in context.objects.values():
for record in table:
obj = session.get(record.__class__, record.id)
if obj:
session.delete(obj)
for table in reversed(Base.metadata.sorted_tables):
if table.name in ("alembic_version", "parameter"):
continue
elif table.name.startswith("lexicon"):
continue
elif table.name == "sample":
continue
Comment on lines +696 to +697

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this was implemented because of a foreign key/non-nullable constraint from sample to field_activity that is going to be addressed in the DB models. @ksmuczynski and I talked about how we need to add cascade="DELETE" to the foreign key definition. I'm going to open a PR with this.

So, if that is the case, I think that handling samples separately from other tables can be removed from this PR.

session.execute(table.delete())
session.commit()
context.objects.clear()


def before_scenario(context, scenario):
Expand All @@ -714,6 +719,13 @@ def after_scenario(context, scenario):
asset = session.scalars(sql).one()
session.delete(asset)
session.commit()
elif "cleanup_samples" in scenario.tags:
# delete all samples created during happy path tests
with session_ctx() as session:
samples = session.query(Sample).all()
for sample in samples:
session.delete(sample)
session.commit()


# ============= EOF =============================================
8 changes: 4 additions & 4 deletions tests/features/steps/well-core-information.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from constants import SRID_WGS84, SRID_UTM_ZONE_13N
from behave import then
from geoalchemy2.shape import to_shape

from core.constants import SRID_WGS84, SRID_UTM_ZONE_13N
from services.util import (
transform_srid,
convert_m_to_ft,
retrieve_latest_polymorphic_history_table_record,
)

from behave import then
from geoalchemy2.shape import to_shape


@then("the response should be in JSON format")
def step_impl(context):
Expand Down
7 changes: 3 additions & 4 deletions tests/features/water-level-csv.feature
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# features/cli/bulk_upload_water_levels.feature

@skip
@cli
@backend
@BDMS-TBD
Expand All @@ -20,7 +19,7 @@ Feature: Bulk upload water level entries from CSV via CLI
# | level_status |
# | data_quality |

@positive @happy_path @BDMS-TBD
@positive @happy_path @BDMS-TBD @cleanup_samples
Scenario: Uploading a valid water level entry CSV containing required and optional fields
Given a valid CSV file for bulk water level entry upload
And my CSV file is encoded in UTF-8 and uses commas as separators
Expand Down Expand Up @@ -56,7 +55,7 @@ Feature: Bulk upload water level entries from CSV via CLI
And stdout includes an array of created water level entry objects
And stderr should be empty

@positive @validation @column_order @BDMS-TBD
@positive @validation @column_order @BDMS-TBD @cleanup_samples
Scenario: Upload succeeds when required columns are present but in a different order
Given my CSV file contains all required headers but in a different column order
And the CSV includes required fields:
Expand All @@ -77,7 +76,7 @@ Feature: Bulk upload water level entries from CSV via CLI
And all water level entries are imported
And stderr should be empty

@positive @validation @extra_columns @BDMS-TBD
@positive @validation @extra_columns @BDMS-TBD @cleanup_samples
Scenario: Upload succeeds when CSV contains extra, unknown columns
Given my CSV file contains extra columns but is otherwise valid
When I run the CLI command:
Expand Down
Loading
Loading