diff --git a/.github/workflows/init.yml b/.github/workflows/init.yml
deleted file mode 100644
index 2aa5cad..0000000
--- a/.github/workflows/init.yml
+++ /dev/null
@@ -1,52 +0,0 @@
-# Workflow runs only once when the template is first used.
-# File can be safely deleted after repo is initialized.
-name: Initialize repository
-on:
- push:
- branches:
- - main
-
-jobs:
- initialize-package:
- name: Initialize the package
- if: ${{github.event.repository.name != 'aind-library-template'}}
- runs-on: ubuntu-latest
- env:
- REPO_NAME: ${{ github.event.repository.name }}
- GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
- steps:
- - name: Checkout
- uses: actions/checkout@v3
- - name: Rename package
- run: |
- pkg_name=$(echo "${REPO_NAME}" | tr - _)
- current_description='description = "Prints messages to stdout. Simple boilerplate for libraries."'
- new_description='description = "Generated from aind-library-template"'
- readme_description='Template for a minimal, basic repository for an AIND library.'
- new_readme_description='Generated from aind-library-template'
- echo "Package Name ${pkg_name}"
- mkdir src/${pkg_name}
- touch src/${pkg_name}/__init__.py
- echo '"""Init package"""' >> src/${pkg_name}/__init__.py
- echo '__version__ = "0.0.0"' >> src/${pkg_name}/__init__.py
- sed -i "s/aind_library_template/${pkg_name}/" pyproject.toml
- sed -i "s/aind-library-template/${REPO_NAME}/" pyproject.toml
- sed -i "s/aind_library_template/${pkg_name}/" docs/source/conf.py
- sed -i "s/${current_description}/${new_description}/" pyproject.toml
- sed -i "/pandas/d" pyproject.toml
- sed -i "s/aind-library-template/${REPO_NAME}/" README.md
- sed -i "s/${readme_description}/${new_readme_description}/" README.md
- - name: Commit changes
- uses: EndBug/add-and-commit@v9
- with:
- default_author: github_actions
- message: "ci: version bump [skip actions]"
- add: '["pyproject.toml", "README.md", "src/*", "docs/source/conf.py"]'
- remove: '["-r src/aind_library_template", "tests/test_message_handler.py"]'
- - name: Add first tag
- run: |
- git tag v0.0.0
- git push origin v0.0.0
- - name: Disable workflow
- run: |
- gh workflow disable -R $GITHUB_REPOSITORY "${{ github.workflow }}"
diff --git a/.github/workflows/test_and_lint.yml b/.github/workflows/test_and_lint.yml
index 7ce7f31..e70d6dc 100644
--- a/.github/workflows/test_and_lint.yml
+++ b/.github/workflows/test_and_lint.yml
@@ -4,6 +4,7 @@ on:
pull_request:
branches:
- main
+ - dev
jobs:
ci:
diff --git a/src/aind_qc_portal/projects/dataset.py b/src/aind_qc_portal/projects/dataset.py
index 8f6f03a..0057c5b 100644
--- a/src/aind_qc_portal/projects/dataset.py
+++ b/src/aind_qc_portal/projects/dataset.py
@@ -3,7 +3,11 @@
import param
from aind_qc_portal.docdb.database import get_project_data
-from aind_qc_portal.utils import format_link, qc_status_color_css, qc_status_link_html
+from aind_qc_portal.utils import (
+ format_link,
+ qc_status_color_css,
+ qc_status_link_html,
+)
from aind_data_schema.core.quality_control import QualityControl, Status
ALWAYS_COLUMNS = ["Subject ID", "Date"]
@@ -35,16 +39,12 @@ def __init__(self, project_name: str, **params):
self.project_name = project_name
self._df = pd.DataFrame(columns=["_id", "timestamp"])
- self.subject_selector = pn.widgets.MultiChoice(
- name="Subject ID"
- )
- self.columns_selector = pn.widgets.MultiChoice(
- name="Columns"
- )
- self.derived_selector = pn.widgets.Select(name="Derived", options=["All", "Raw", "Derived"])
- self.type_selector = pn.widgets.Select(
- name="Type"
+ self.subject_selector = pn.widgets.MultiChoice(name="Subject ID")
+ self.columns_selector = pn.widgets.MultiChoice(name="Columns")
+ self.derived_selector = pn.widgets.Select(
+ name="Derived", options=["All", "Raw", "Derived"]
)
+ self.type_selector = pn.widgets.Select(name="Type")
self.status_selector = pn.widgets.Select(
name="QC Status", options=QC_STATUS_OPTIONS
)
@@ -52,7 +52,11 @@ def __init__(self, project_name: str, **params):
self._get_assets()
self.subject_selector.options = self.subjects
- self.columns_selector.options = [column for column in self.columns if column not in ALWAYS_COLUMNS + HIDDEN_COLUMNS]
+ self.columns_selector.options = [
+ column
+ for column in self.columns
+ if column not in ALWAYS_COLUMNS + HIDDEN_COLUMNS
+ ]
self.type_selector.options = ["All"] + self.types
def _get_assets(self):
@@ -102,7 +106,9 @@ def _get_assets(self):
record_data = {
"_id": record.get("_id"),
- "Raw Data": record.get("data_description", {}).get("data_level")
+ "Raw Data": record.get("data_description", {}).get(
+ "data_level"
+ )
== "raw",
"project_name": record.get("data_description", {}).get(
"project_name"
@@ -141,11 +147,16 @@ def _get_assets(self):
lambda x: ", ".join(x) if x else None
)
self._df["QC Status"] = self._df.apply(
- lambda row: qc_status_link_html(row["QC Status"], row["qc_link"], row["QC Status"]), axis=1
+ lambda row: qc_status_link_html(
+ row["QC Status"], row["qc_link"], row["QC Status"]
+ ),
+ axis=1,
)
print(self._df["QC Status"].values[0])
- self._df.drop(columns=["qc_link", "operator", "session_start_time", "location"])
+ self._df.drop(
+ columns=["qc_link", "operator", "session_start_time", "location"]
+ )
# Sort dataframe by time and then by subject ID
self._df.sort_values(by="timestamp", ascending=True, inplace=True)
@@ -168,13 +179,12 @@ def _data_filtered(self) -> pd.DataFrame:
if self.derived_filter != "All":
filtered_df = filtered_df[
- filtered_df["Raw Data"] == (True if self.derived_filter == "Raw" else False)
+ filtered_df["Raw Data"]
+ == (True if self.derived_filter == "Raw" else False)
]
if self.type_filter != "All":
- filtered_df = filtered_df[
- filtered_df["Type"] == self.type_filter
- ]
+ filtered_df = filtered_df[filtered_df["Type"] == self.type_filter]
if self.status_filter != "All":
filtered_df = filtered_df[
diff --git a/src/aind_qc_portal/projects/project_view.py b/src/aind_qc_portal/projects/project_view.py
index 977c678..2b4b4f4 100644
--- a/src/aind_qc_portal/projects/project_view.py
+++ b/src/aind_qc_portal/projects/project_view.py
@@ -41,12 +41,11 @@ def __init__(self, project_name: str, dataset: ProjectDataset):
self.history_chart = self.history_panel()
if hasattr(self.history_chart, "selection"):
self.selection_history_chart = pn.bind(
- self.selection_history_panel, self.history_chart.selection.param.brush
+ self.selection_history_panel,
+ self.history_chart.selection.param.brush,
)
else:
- self.selection_history_chart = pn.widgets.StaticText(
- value=""
- )
+ self.selection_history_chart = pn.widgets.StaticText(value="")
@property
def has_data(self):
@@ -59,8 +58,7 @@ def get_asset_count(self):
return len(self.dataset.data_filtered())
def update_subject_selector(self, event):
- """Update the subject selector based on the brush selection
- """
+ """Update the subject selector based on the brush selection"""
if event.new.get("Subject ID") is not None:
self.dataset.subject_selector.value = event.new["Subject ID"]
else:
@@ -76,8 +74,10 @@ def history_panel(self):
data = self.dataset.data
# Check that timestamp column has values
- if data['timestamp'].isnull().all():
- return pn.widgets.StaticText(value="Data processing error: project is missing timestamp data in some assets. Please reach out to scientific computing for help repairing your metadata.")
+ if data["timestamp"].isnull().all():
+ return pn.widgets.StaticText(
+ value="Data processing error: project is missing timestamp data in some assets. Please reach out to scientific computing for help repairing your metadata."
+ )
# Calculate the time range to show on the x axis
(min_range, max_range, range_unit, format) = df_timestamp_range(
@@ -102,7 +102,9 @@ def history_panel(self):
alt.Tooltip("Date:T", title="Date"),
],
color=alt.condition(
- self.brush, alt.Color("Subject ID:N"), alt.value("lightgray")
+ self.brush,
+ alt.Color("Subject ID:N"),
+ alt.value("lightgray"),
),
href=alt.Href("qc_link:N"),
)
@@ -125,7 +127,9 @@ def selection_history_panel(self, selection):
data = self.dataset.data_filtered()
if data.empty:
- return pn.widgets.StaticText(value="No data found for the selected filters")
+ return pn.widgets.StaticText(
+ value="No data found for the selected filters"
+ )
# Calculate the time range to show on the x axis
(min_range, max_range, range_unit, format) = df_timestamp_range(
@@ -170,12 +174,14 @@ def selection_history_panel(self, selection):
return pn.pane.Vega(chart, sizing_mode="stretch_width")
- def _panel(self,
- subject_filter,
- derived_filter,
- columns_filter,
- type_filter,
- status_filter) -> pn.Column:
+ def _panel(
+ self,
+ subject_filter,
+ derived_filter,
+ columns_filter,
+ type_filter,
+ status_filter,
+ ) -> pn.Column:
"""Return panel object"""
self.dataset.subject_filter = subject_filter
@@ -192,11 +198,15 @@ def _panel(self,
def panel(self):
- return pn.Column(self.history_chart, pn.bind(
- self._panel,
- subject_filter=self.dataset.subject_selector,
- derived_filter=self.dataset.derived_selector,
- columns_filter=self.dataset.columns_selector,
- type_filter=self.dataset.type_selector,
- status_filter=self.dataset.status_selector,
- ), styles=OUTER_STYLE)
+ return pn.Column(
+ self.history_chart,
+ pn.bind(
+ self._panel,
+ subject_filter=self.dataset.subject_selector,
+ derived_filter=self.dataset.derived_selector,
+ columns_filter=self.dataset.columns_selector,
+ type_filter=self.dataset.type_selector,
+ status_filter=self.dataset.status_selector,
+ ),
+ styles=OUTER_STYLE,
+ )
diff --git a/src/aind_qc_portal/qc_project_app.py b/src/aind_qc_portal/qc_project_app.py
index ae860da..3e746ae 100644
--- a/src/aind_qc_portal/qc_project_app.py
+++ b/src/aind_qc_portal/qc_project_app.py
@@ -91,9 +91,7 @@ def panel(self):
dataset.subject_selector.value = dataset.subject_filter
dataset.derived_selector.value = dataset.derived_filter
dataset.columns_selector.value = [
- column
- for column in dataset.columns_filter
- if column not in ALWAYS_COLUMNS
+ column for column in dataset.columns_filter if column not in ALWAYS_COLUMNS
]
dataset.type_selector.value = dataset.type_filter
dataset.status_selector.value = dataset.status_filter
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 339fb40..478abf2 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -12,20 +12,35 @@
df_timestamp_range,
replace_markdown_with_html,
qc_status_color_css,
- bincount2D
+ bincount2D,
)
class TestUtils(unittest.TestCase):
def test_format_link(self):
- self.assertEqual(format_link("http://example.com"), 'link')
- self.assertEqual(format_link("http://example.com", "Example"), 'Example')
+ self.assertEqual(
+ format_link("http://example.com"),
+ 'link',
+ )
+ self.assertEqual(
+ format_link("http://example.com", "Example"),
+ 'Example',
+ )
def test_status_html(self):
- self.assertEqual(qc_status_html(Status.PASS), 'Pass')
- self.assertEqual(qc_status_html(Status.PENDING), 'Pending')
- self.assertEqual(qc_status_html(Status.FAIL), 'Fail')
+ self.assertEqual(
+ qc_status_html(Status.PASS),
+ 'Pass',
+ )
+ self.assertEqual(
+ qc_status_html(Status.PENDING),
+ 'Pending',
+ )
+ self.assertEqual(
+ qc_status_html(Status.FAIL),
+ 'Fail',
+ )
def test_df_timestamp_range(self):
data = {
@@ -41,13 +56,24 @@ def test_df_timestamp_range(self):
self.assertEqual(fmt, "%b %d")
def test_md_style(self):
- self.assertEqual(replace_markdown_with_html(12, "test"), 'test')
+ self.assertEqual(
+ replace_markdown_with_html(12, "test"),
+ 'test',
+ )
def test_qc_color(self):
- self.assertEqual(qc_status_color_css("No QC"), "background-color: #FFB71B")
- self.assertEqual(qc_status_color_css("Pass"), "background-color: #1D8649")
- self.assertEqual(qc_status_color_css("Fail"), "background-color: #FF5733")
- self.assertEqual(qc_status_color_css("Pending"), "background-color: #2A7DE1")
+ self.assertEqual(
+ qc_status_color_css("No QC"), "background-color: #FFB71B"
+ )
+ self.assertEqual(
+ qc_status_color_css("Pass"), "background-color: #1D8649"
+ )
+ self.assertEqual(
+ qc_status_color_css("Fail"), "background-color: #FF5733"
+ )
+ self.assertEqual(
+ qc_status_color_css("Pending"), "background-color: #2A7DE1"
+ )
def test_bincount2D(self):
x = np.array([1, 2, 2, 3])
@@ -57,17 +83,25 @@ def test_bincount2D(self):
self.assertTrue(np.array_equal(xscale, np.array([1, 2, 3])))
self.assertTrue(np.array_equal(yscale, np.array([4, 5, 6])))
- @patch('aind_qc_portal.utils.pn')
+ @patch("aind_qc_portal.utils.pn")
def test_set_background(self, mock_pn):
mock_pn.config.raw_css = [] # Mock raw_css to ensure a clean state
- mock_pn.state.location.query_params = {} # Mock query_params to ensure no background param
+ mock_pn.state.location.query_params = (
+ {}
+ ) # Mock query_params to ensure no background param
format_css_background()
- self.assertIn("background-color: #003057", mock_pn.config.raw_css[0]) # Default dark_blue color
+ self.assertIn(
+ "background-color: #003057", mock_pn.config.raw_css[0]
+ ) # Default dark_blue color
mock_pn.config.raw_css = [] # Reset mock raw_css
- mock_pn.state.location.query_params = {"background": "light_blue"} # Mock query_params with light_blue
+ mock_pn.state.location.query_params = {
+ "background": "light_blue"
+ } # Mock query_params with light_blue
format_css_background()
- self.assertIn("background-color: #2A7DE1", mock_pn.config.raw_css[0]) # light_blue color
+ self.assertIn(
+ "background-color: #2A7DE1", mock_pn.config.raw_css[0]
+ ) # light_blue color
if __name__ == "__main__":