Skip to content

[389] Support ingest from postgresql with testing - #477

Open
dbashford-NOAA wants to merge 50 commits into
echostack-org:mainfrom
dbashford-NOAA:389_db_bio_ingest
Open

dbashford-NOAA wants to merge 50 commits into
echostack-org:mainfrom
dbashford-NOAA:389_db_bio_ingest

Conversation

@dbashford-NOAA

Copy link
Copy Markdown
Collaborator

Resolves #389

Added a function to load bio data from a postgres db as an alternative to loading from a CSV

Cleaned version of PR #415

@dbashford-NOAA
dbashford-NOAA marked this pull request as ready for review March 18, 2026 16:48
@dbashford-NOAA

Copy link
Copy Markdown
Collaborator Author

@leewujung
I opened this new PR for this work because it was easier to push a new branch instead of trying to fix all the upstream conflicts in the other one (#415) which can probably just be closed now.

Let me know if there is anything here I should change.

pre-commit-ci Bot and others added 5 commits March 26, 2026 11:36
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.6 → v0.15.7](astral-sh/ruff-pre-commit@v0.15.6...v0.15.7)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.7 → v0.15.8](astral-sh/ruff-pre-commit@v0.15.7...v0.15.8)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.8 → v0.15.9](astral-sh/ruff-pre-commit@v0.15.8...v0.15.9)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
…#485)

Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.13.0 to 1.14.0.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](pypa/gh-action-pypi-publish@v1.13.0...v1.14.0)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-version: 1.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.9 → v0.15.10](astral-sh/ruff-pre-commit@v0.15.9...v0.15.10)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
@leewujung

Copy link
Copy Markdown
Member

@dbashford-NOAA : Agreed! I just closed #415.

leewujung
leewujung previously approved these changes Apr 14, 2026

@leewujung leewujung left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @dbashford-NOAA ! I think the code/tests look good on my side. Just requested @aliciabillings-noaa to review. :)

brandynlucca and others added 9 commits April 19, 2026 07:46
* Fix number proportions normalization

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Quick addendum to `hake_2019.py` with associated workflow and bug-fixes.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.10 → v0.15.11](astral-sh/ruff-pre-commit@v0.15.10...v0.15.11)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.11 → v0.15.12](astral-sh/ruff-pre-commit@v0.15.11...v0.15.12)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.12 → v0.15.13](astral-sh/ruff-pre-commit@v0.15.12...v0.15.13)
- [github.com/psf/black-pre-commit-mirror: 26.3.1 → 26.5.0](psf/black-pre-commit-mirror@26.3.1...26.5.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
…project-metadata

changing the org name path
* just changing the org name!

* Migrate dependency management to pyproject.toml

- Move dev/docs deps to pyproject extras
- Update CI and RTD install workflows
- Remove legacy requirements/config files
- Refresh installation documentation

* Update pyproject.toml

Co-authored-by: Brandyn Lucca <45861253+brandynlucca@users.noreply.github.com>

* Re-adding missing comma

---------

Co-authored-by: Brandyn Lucca <45861253+brandynlucca@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.13 → v0.15.14](astral-sh/ruff-pre-commit@v0.15.13...v0.15.14)
- [github.com/psf/black-pre-commit-mirror: 26.5.0 → 26.5.1](psf/black-pre-commit-mirror@26.5.0...26.5.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
pre-commit-ci Bot and others added 26 commits June 2, 2026 09:50
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.14 → v0.15.15](astral-sh/ruff-pre-commit@v0.15.14...v0.15.15)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.15 → v0.15.16](astral-sh/ruff-pre-commit@v0.15.15...v0.15.16)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.16 → v0.15.18](astral-sh/ruff-pre-commit@v0.15.16...v0.15.18)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.18 → v0.15.20](astral-sh/ruff-pre-commit@v0.15.18...v0.15.20)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6 to 7.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](actions/setup-python@v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.14.0 to 1.14.1.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](pypa/gh-action-pypi-publish@v1.14.0...v1.14.1)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-version: 1.14.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.20 → v0.16.0](astral-sh/ruff-pre-commit@v0.15.20...v0.16.0)
- [github.com/codespell-project/codespell: v2.4.2 → v2.4.3](codespell-project/codespell@v2.4.2...v2.4.3)
…-update-config

[pre-commit.ci] pre-commit autoupdate
…thub_actions/actions/setup-python-7

Bump actions/setup-python from 6 to 7
…thub_actions/pypa/gh-action-pypi-publish-1.14.1

Bump pypa/gh-action-pypi-publish from 1.14.0 to 1.14.1
…#511)

Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.14.1 to 1.14.2.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](pypa/gh-action-pypi-publish@v1.14.1...v1.14.2)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-version: 1.14.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.16.0 → v0.16.1](astral-sh/ruff-pre-commit@v0.16.0...v0.16.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.16.1 → v0.16.2](astral-sh/ruff-pre-commit@v0.16.1...v0.16.2)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.16.2 → v0.16.3](astral-sh/ruff-pre-commit@v0.16.2...v0.16.3)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.16.3 → v0.16.4](astral-sh/ruff-pre-commit@v0.16.3...v0.16.4)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.16.4 → v0.16.5](astral-sh/ruff-pre-commit@v0.16.4...v0.16.5)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
# Conflicts:
#	echopop/ingest/biological.py
#	requirements-dev.txt
#	requirements.txt
…io_ingest

# Conflicts:
#	requirements-dev.txt
#	requirements.txt

@brandynlucca brandynlucca left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@dbashford-NOAA I suggested adding requires-python/python-version fields in pr.yaml and project.toml. That should allow the tests to pass for 3.14; effecting those changes allowed my local tox tests to pass.

There was one exception: I was not able to run the acutal PostgreSQL database tests since I can't run Docker locally. Could we make the database tests runnable locally without Docker? Currently, the fixture skips all three when Docker or testcontainers is unavailable, so a passing local run can leave database ingestion untested. That makes it harder for contributors to catch regressions before submitting changes.

I suggest using an automatically managed local PostgreSQL instance while retaining Docker coverage in CI. Both paths could reuse the existing tests and seed data, allowing contributors to verify the same behavior without manually configuring a database. Setup failures should also produce errors rather than skips, so broken infrastructure cannot silently reduce coverage.

I tested this approach locally and the three previously skipped database tests passed.

Comment thread .github/workflows/pr.yaml
@@ -18,19 +18,29 @@ jobs:
python-version: ["3.12", "3.13"]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
python-version: ["3.12", "3.13"]
python-version: ["3.12", "3.13", "3.14"]

Comment thread pyproject.toml
"Programming Language :: Python :: 3.12",
"Topic :: Scientific/Engineering"
]
requires-python = ">=3.12, <3.14"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
requires-python = ">=3.12, <3.15"

Comment thread .github/workflows/pr.yaml
pip install -e .
python -m pip install -e ".[dev]"
- name: Test with pytest
run: |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
run: |
# Fixtures also exercise Docker automatically on Ubuntu runners.
run: |

Comment thread .github/workflows/pr.yaml
Comment on lines +29 to +38
- name: Setup PostgreSQL Binaries
# GitHub action to set up postgreSQL for all 3 platforms
uses: ikalnytskyi/action-setup-postgres@v8
with:
username: test_user
password: postgres
database: test
port: 5432
postgres-version: '14'
id: postgres

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
- name: Setup PostgreSQL Binaries
# GitHub action to set up postgreSQL for all 3 platforms
uses: ikalnytskyi/action-setup-postgres@v8
with:
username: test_user
password: postgres
database: test
port: 5432
postgres-version: '14'
id: postgres

See my overall comment concerning this.

Comment thread pyproject.toml
dev = [
"black",
"coverage",
"isort",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
"isort",
"isort",
"pgembed==0.2.0",

@@ -1,5 +1,92 @@
import os

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
import os
import os
import sys
from importlib.resources import files

from pathlib import Path

import pandas as pd
import pytest

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
import pytest
import pytest
from pytest_postgresql import factories

TEST_DATA_ROOT = HERE.parent / "test_data"
TEST_SQL_FILE = TEST_DATA_ROOT / "ingest" / "test_bio_data.sql"


Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
# Bundled binaries let plain pytest run locally without Docker or server setup.
native_postgres_process = factories.postgresql_proc(
executable=str(
files("pgembed") / "pginstall" / "bin" / ("pg_ctl.exe" if os.name == "nt" else "pg_ctl")
),
host="127.0.0.1",
port=None,
user="test_user",
password="postgres",
dbname="test",
)
native_postgres = factories.postgresql("native_postgres_process")

Comment on lines +15 to +47
"""
Session-scoped fixture to get database connection.

- In GitHub Actions: Uses the postgres service from the workflow
- Locally: Uses Testcontainers if Docker is available, skips if not
"""
is_github_action = os.environ.get("GITHUB_ACTIONS")

if is_github_action:
# In GitHub Actions use the postgres service from workflow
yield type(
"obj",
(object,),
{
"get_connection_url": lambda self: "postgresql+psycopg://test_user:postgres@localhost:5432/test",
"get_container_host_ip": lambda self: "localhost",
"get_exposed_port": lambda self, port: 5432,
},
)()
else:
# Local development
try:
from testcontainers.postgres import PostgresContainer

container = PostgresContainer(
image="postgres:16", username="test_user", password="postgres", dbname="test"
)
container.start()
yield container
container.stop()
except Exception as e:
# Docker not available - skip integration tests
pytest.skip(f"Docker must be running for Testcontainers: {e}")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
"""
Session-scoped fixture to get database connection.
- In GitHub Actions: Uses the postgres service from the workflow
- Locally: Uses Testcontainers if Docker is available, skips if not
"""
is_github_action = os.environ.get("GITHUB_ACTIONS")
if is_github_action:
# In GitHub Actions use the postgres service from workflow
yield type(
"obj",
(object,),
{
"get_connection_url": lambda self: "postgresql+psycopg://test_user:postgres@localhost:5432/test",
"get_container_host_ip": lambda self: "localhost",
"get_exposed_port": lambda self, port: 5432,
},
)()
else:
# Local development
try:
from testcontainers.postgres import PostgresContainer
container = PostgresContainer(
image="postgres:16", username="test_user", password="postgres", dbname="test"
)
container.start()
yield container
container.stop()
except Exception as e:
# Docker not available - skip integration tests
pytest.skip(f"Docker must be running for Testcontainers: {e}")
"""Exercise the existing PostgreSQL container on Linux CI."""
from testcontainers.community.postgres import PostgresContainer
with PostgresContainer(
image="postgres:16",
username="test_user",
password="postgres",
dbname="test",
driver="psycopg",
) as container:
yield container

Comment on lines +50 to +89
@pytest.fixture(scope="session")
def database_credentials(postgres_container):
"""
Session-scoped fixture to:
1. Connect to the PostgreSQL database (CI or local).
2. Load 'test_bio_data.sql' into it.
3. Yield the credentials dictionary in the format expected by load_biodata_db_views.

Returns dict with keys: host, port, dbname, user, password, schema
"""

host = postgres_container.get_container_host_ip()
port = postgres_container.get_exposed_port(5432)

creds = {
"host": host,
"port": port,
"dbname": "test",
"user": "test_user",
"password": "postgres",
"schema": "public",
}

db_url = (
f"postgresql+psycopg://"
f"{creds['user']}:{creds['password']}@"
f"{creds['host']}:{creds['port']}/"
f"{creds['dbname']}"
)

try:
engine = create_engine(db_url)
with engine.begin() as connection:
with open(TEST_SQL_FILE) as f:
sql_script = f.read()
connection.execute(text(sql_script))
except Exception as e:
pytest.fail(f"Failed to load {TEST_SQL_FILE}: {e}")

yield creds

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
@pytest.fixture(scope="session")
def database_credentials(postgres_container):
"""
Session-scoped fixture to:
1. Connect to the PostgreSQL database (CI or local).
2. Load 'test_bio_data.sql' into it.
3. Yield the credentials dictionary in the format expected by load_biodata_db_views.
Returns dict with keys: host, port, dbname, user, password, schema
"""
host = postgres_container.get_container_host_ip()
port = postgres_container.get_exposed_port(5432)
creds = {
"host": host,
"port": port,
"dbname": "test",
"user": "test_user",
"password": "postgres",
"schema": "public",
}
db_url = (
f"postgresql+psycopg://"
f"{creds['user']}:{creds['password']}@"
f"{creds['host']}:{creds['port']}/"
f"{creds['dbname']}"
)
try:
engine = create_engine(db_url)
with engine.begin() as connection:
with open(TEST_SQL_FILE) as f:
sql_script = f.read()
connection.execute(text(sql_script))
except Exception as e:
pytest.fail(f"Failed to load {TEST_SQL_FILE}: {e}")
yield creds
@pytest.fixture(
params=(
["native", "docker"]
if os.environ.get("GITHUB_ACTIONS") == "true" and sys.platform == "linux"
else ["native"]
)
)
def database_credentials(request):
"""
Fixture to:
1. Start native PostgreSQL locally and on CI; also test Docker on Linux CI.
2. Load 'test_bio_data.sql' into it.
3. Return the credentials dictionary expected by load_biodata_db_views.
Returns dict with keys: host, port, dbname, user, password, schema
"""
backend = request.param
if backend == "native":
connection = request.getfixturevalue("native_postgres")
host, port = connection.info.host, connection.info.port
dbname = connection.info.dbname
else:
container = request.getfixturevalue("postgres_container")
host, port = container.get_container_host_ip(), container.get_exposed_port(5432)
dbname = "test"
creds = {
"host": host,
"port": port,
"dbname": dbname,
"user": "test_user",
"password": "postgres",
"schema": "public",
}
db_url = (
f"postgresql+psycopg://"
f"{creds['user']}:{creds['password']}@"
f"{creds['host']}:{creds['port']}/"
f"{creds['dbname']}"
)
engine = create_engine(db_url)
try:
with engine.begin() as connection:
with open(TEST_SQL_FILE, encoding="utf-8") as f:
sql_script = f.read()
connection.execute(text(sql_script))
except Exception as e:
pytest.fail(f"Failed to load {TEST_SQL_FILE}: {e}")
finally:
engine.dispose()
return creds

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add the functionality to ingest biological data directly from database views

5 participants