Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4d4573b
Add proposed_changes table to models/utils
Jan 9, 2026
b476082
PIRLinker: Remove redundant get_question_data code
Jan 12, 2026
79d7d84
DashboardUtils: Create id_column dynamically in .search_matches
Jan 12, 2026
422173b
Dashboard: Refactor review confirm
Jan 12, 2026
0afc629
Search: Refactor confirm button
Jan 12, 2026
799fb3c
Dashboard: send question table HTML with store action
Jan 13, 2026
68e2a4e
Dashboard: index.py now creates missing tables
Jan 13, 2026
6416546
Dashboard: Handle incoming html in review.py
Jan 13, 2026
ecc9b1b
Finalize: Render a table on the finalize page
Jan 14, 2026
5d22aba
Dashboard: Drafting finalize page
Jan 15, 2026
f3826c8
Dashboard: Correct ID sort in review.py
Jan 15, 2026
e0c7b40
SQL Models: Flashcard view
Jan 15, 2026
948ca4f
Flashcard: Confirm button handling
Jan 18, 2026
4c0ae04
Finalize: WIP logic for committing and denying links
Jan 18, 2026
2e80dfc
Dashboard-Finalize: Tests for finalize
Jan 20, 2026
e5e0d96
Dashboard: Tests for review.link
Jan 21, 2026
d3be581
PIRLinker: Fix == to is
Jan 21, 2026
09c9fa9
Tests.dashboard.finalize: Remove driver usage to allow running in cloud
Jan 22, 2026
a341175
Finalize: Add number displayed dropdown
Jan 22, 2026
ee179dc
Tests.dashboard.finalize_ui: Tests for finalize ui
Jan 22, 2026
b8496a4
Dashboard: Ensure correct config is used for dashboard
Jan 22, 2026
a1a6637
PIRLinker: Revert to == from IS. Note noqa
Jan 22, 2026
ad9f7c0
Dashboard: Margin on number-displayed
Jan 22, 2026
1aa8437
Dashboard.finalize: Fix number displayed
Jan 23, 2026
ccbe9f9
Code formatted with black
RGilliard-ACF Jan 25, 2026
7f19eba
Bug Correction: Adjust imports
Jan 26, 2026
d1bbee3
Merge branch 'main' into feat-finalize-page
Jan 26, 2026
10fd83b
Merge branch 'feat-finalize-page' of https://github.com/HHS/ACF-pir-d…
Jan 26, 2026
7c2385c
Dashboard.index: Remove .create_db
Jan 26, 2026
f2e1903
Adding alembic to the dependencies for future DB management
Jan 26, 2026
966c056
Dashboard: Provide HTML to review/link from search page
Jan 29, 2026
a7426b2
Dashboard.review: Correct link_dict
Jan 29, 2026
ff87c42
dashboard_utils: Correct QuestionLinker logic
Jan 29, 2026
c054a46
Test fixes
Jan 29, 2026
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
44 changes: 44 additions & 0 deletions alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# A generic, single database configuration.

[alembic]

# database URL. This is consumed by the user-maintained env.py script only.
# other means of configuring database URLs may be customized within the env.py
# file.
sqlalchemy.url = driver://user:pass@localhost/dbname


# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARNING
handlers = console
qualname =

[logger_sqlalchemy]
level = WARNING
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
1 change: 1 addition & 0 deletions alembic/README
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pyproject configuration, based on the generic configuration.
83 changes: 83 additions & 0 deletions alembic/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from logging.config import fileConfig

from sqlalchemy import engine_from_config, pool

from alembic import context
from pir_pipeline.config import DB_CONFIG, DB_NAME
from pir_pipeline.models.pir_sql_models import sql_metadata
from pir_pipeline.utils.SQLAlchemyUtils import SQLAlchemyUtils

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

# Interpret the config file for Python logging.
# This line sets up loggers basically.
if config.config_file_name is not None:
fileConfig(config.config_file_name)

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = sql_metadata

# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
sql_utils = SQLAlchemyUtils(**DB_CONFIG, database=DB_NAME)
config.set_main_option(
"sqlalchemy.url",
sql_utils._engine.url.__to_string__(hide_password=False).replace("%", "%%"),
)


def run_migrations_offline() -> None:
"""Run migrations in 'offline' mode.

This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.

Calls to context.execute() here emit the given string to the
script output.

"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)

with context.begin_transaction():
context.run_migrations()


def run_migrations_online() -> None:
"""Run migrations in 'online' mode.

In this scenario we need to create an Engine
and associate a connection with the context.

"""
connectable = engine_from_config(
config.get_section(config.config_ini_section, {}),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)

with connectable.connect() as connection:
context.configure(connection=connection, target_metadata=target_metadata)

with context.begin_transaction():
context.run_migrations()


if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
28 changes: 28 additions & 0 deletions alembic/script.py.mako
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""${message}

Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
${imports if imports else ""}

# revision identifiers, used by Alembic.
revision: str = ${repr(up_revision)}
down_revision: Union[str, Sequence[str], None] = ${repr(down_revision)}
branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}


def upgrade() -> None:
"""Upgrade schema."""
${upgrades if upgrades else "pass"}


def downgrade() -> None:
"""Downgrade schema."""
${downgrades if downgrades else "pass"}
1 change: 1 addition & 0 deletions code/serve_qa_dashboard.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
cd ~/repos/ACF-pir-data/
source .venv/bin/activate
export LOADING_DASHBOARD="True"
google-chrome http://localhost:8080 &>/dev/null &
waitress-serve --host 127.0.0.1 --call "pir_pipeline.dashboard:create_app"
4 changes: 2 additions & 2 deletions code/uqid_bug_correction.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
from typing import MutableSequence

from pandas import DataFrame
from sqlalchemy import func, or_, select, text, Select, bindparam
from sqlalchemy import bindparam, func, or_, select, text

os.environ["RDS_CREDENTIALS"] = "True"

from pir_pipeline.config import DB_CONFIG
from pir_pipeline.linking.PIRLinker import PIRLinker
from pir_pipeline.utils.SQLAlchemyUtils import SQLAlchemyUtils
from pir_pipeline.utils.dashboard_utils import QuestionLinker
from pir_pipeline.utils.SQLAlchemyUtils import SQLAlchemyUtils

SQL_UTILS = SQLAlchemyUtils(**DB_CONFIG, database="pir_data")
QUESTION = SQL_UTILS.tables["question"]
Expand Down
89 changes: 87 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ dependencies = [
"mysql-connector-python", "sphinx", "pandas", "python-dotenv",
"fuzzywuzzy", "python-Levenshtein", "pytest", "openpyxl", "xlrd",
"pydantic", "Flask", "SQLAlchemy", "sqlalchemy-utils", "psycopg[binary]",
"requests", "selenium", "coverage", "boto3", "waitress"
"requests", "selenium", "coverage", "boto3", "waitress", "alembic"
]

[build-system]
Expand All @@ -27,4 +27,89 @@ build-backend = "setuptools.build_meta"
Homepage = "https://github.com/HHS/ACF-pir-data"

[tool.pytest.ini_options]
testpaths = ["tests"]
testpaths = ["tests"]

[tool.alembic]

# path to migration scripts.
# this is typically a path given in POSIX (e.g. forward slashes)
# format, relative to the token %(here)s which refers to the location of this
# ini file
script_location = "%(here)s/alembic"

# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
# Uncomment the line below if you want the files to be prepended with date and time
# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
# for all available tokens
# file_template = "%%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s"
# Or organize into date-based subdirectories (requires recursive_version_locations = true)
# file_template = "%%(year)d/%%(month).2d/%%(day).2d_%%(hour).2d%%(minute).2d_%%(second).2d_%%(rev)s_%%(slug)s"

# additional paths to be prepended to sys.path. defaults to the current working directory.
prepend_sys_path = [
"."
]

# timezone to use when rendering the date within the migration file
# as well as the filename.
# If specified, requires the tzdata library which can be installed by adding
# `alembic[tz]` to the pip requirements.
# string value is passed to ZoneInfo()
# leave blank for localtime
# timezone =

# max length of characters to apply to the "slug" field
# truncate_slug_length = 40

# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false

# set to 'true' to allow .pyc and .pyo files without
# a source .py file to be detected as revisions in the
# versions/ directory
# sourceless = false

# version location specification; This defaults
# to <script_location>/versions. When using multiple version
# directories, initial revisions must be specified with --version-path.
# version_locations = [
# "%(here)s/alembic/versions",
# "%(here)s/foo/bar"
# ]


# set to 'true' to search source files recursively
# in each "version_locations" directory
# new in Alembic version 1.10
# recursive_version_locations = false

# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = "utf-8"

# This section defines scripts or Python functions that are run
# on newly generated revision scripts. See the documentation for further
# detail and examples
# [[tool.alembic.post_write_hooks]]
# format using "black" - use the console_scripts runner,
# against the "black" entrypoint
# name = "black"
# type = "console_scripts"
# entrypoint = "black"
# options = "-l 79 REVISION_SCRIPT_FILENAME"
#
# [[tool.alembic.post_write_hooks]]
# lint with attempts to fix using "ruff" - use the module runner, against the "ruff" module
# name = "ruff"
# type = "module"
# module = "ruff"
# options = "check --fix REVISION_SCRIPT_FILENAME"
#
# [[tool.alembic.post_write_hooks]]
# Alternatively, use the exec runner to execute a binary found on your PATH
# name = "ruff"
# type = "exec"
# executable = "ruff"
# options = "check --fix REVISION_SCRIPT_FILENAME"

2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ openpyxl==3.1.5
outcome==1.3.0.post0
packaging==25.0
pandas==2.2.3
-e git+https://github.com/HHS/ACF-pir-data.git@0104f01060b03cdcbef74e0f8008782c8059cd32#egg=pir_pipeline
-e git+https://github.com/HHS/ACF-pir-data.git@d1bbee31e9490b6b089a91ffaed915bd9eff2364#egg=pir_pipeline
pluggy==1.5.0
psycopg==3.2.7
psycopg-binary==3.2.7
Expand Down
3 changes: 2 additions & 1 deletion src/pir_pipeline/dashboard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@ def create_app(test_config: dict = None, **kwargs) -> Flask:

db.init_app(app)

from pir_pipeline.dashboard import index, review, search
from pir_pipeline.dashboard import finalize, index, review, search

app.register_blueprint(index.bp)
app.add_url_rule("/", endpoint="index")

app.register_blueprint(search.bp)
app.register_blueprint(review.bp)
app.register_blueprint(finalize.bp)

return app
Loading
Loading