Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc fixes #1192

Merged
merged 11 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ dj.FreeTable(dj.conn(), "common_session.session_group").drop()
- Remove numpy version restriction #1169
- Merge table delete removes orphaned master entries #1164
- Edit `merge_fetch` to expect positional before keyword arguments #1181
- Allow part restriction `SpyglassMixinPart.delete` #1192

### Pipelines

Expand All @@ -51,8 +52,11 @@ dj.FreeTable(dj.conn(), "common_session.session_group").drop()
- Improve electrodes import efficiency #1125
- Fix logger method call in `common_task` #1132
- Export fixes #1164
- Allow `get_abs_path` to add selection entry.
- Log restrictions and joins.
- Allow `get_abs_path` to add selection entry. #1164
- Log restrictions and joins. #1164
- Check if querying table inherits mixin in `fetch_nwb`. #1192
- Ensure externals entries before adding to export. #1192
- Error specificity in `LabMemberInfo` #1192

- Decoding

Expand All @@ -73,6 +77,7 @@ dj.FreeTable(dj.conn(), "common_session.session_group").drop()
`open-cv` #1168
- `VideoMaker` class to process frames in multithreaded batches #1168, #1174
- `TrodesPosVideo` updates for `matplotlib` processor #1174
- User prompt if ambiguous insert in `DLCModelSource` #1192

- Spike Sorting

Expand Down
6 changes: 4 additions & 2 deletions src/spyglass/common/common_lab.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,11 @@ def get_djuser_name(cls, dj_user) -> str:
)

if len(query) != 1:
remedy = f"delete {len(query)-1}" if len(query) > 1 else "add one"
raise ValueError(
f"Could not find name for datajoint user {dj_user}"
+ f" in common.LabMember.LabMemberInfo: {query}"
f"Could not find exactly 1 datajoint user {dj_user}"
+ " in common.LabMember.LabMemberInfo. "
+ f"Please {remedy}: {query}"
)

return query[0]
Expand Down
40 changes: 21 additions & 19 deletions src/spyglass/common/common_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@
from typing import List, Union

import datajoint as dj
from datajoint import FreeTable
from datajoint import config as dj_config
from pynwb import NWBHDF5IO

from spyglass.common.common_nwbfile import AnalysisNwbfile, Nwbfile
from spyglass.settings import export_dir, test_mode
from spyglass.settings import test_mode
from spyglass.utils import SpyglassMixin, SpyglassMixinPart, logger
from spyglass.utils.dj_graph import RestrGraph
from spyglass.utils.dj_helper_fn import (
Expand Down Expand Up @@ -174,7 +172,6 @@ def list_file_paths(self, key: dict, as_dict=True) -> list[str]:
Return as a list of dicts: [{'file_path': x}]. Default True.
If False, returns a list of strings without key.
"""
file_table = self * self.File & key
unique_fp = {
*[
AnalysisNwbfile().get_abs_path(p)
Expand Down Expand Up @@ -210,21 +207,26 @@ def _add_externals_to_restr_graph(
restr_graph : RestrGraph
The updated RestrGraph
"""
raw_tbl = self._externals["raw"]
raw_name = raw_tbl.full_table_name
raw_restr = (
"filepath in ('" + "','".join(self._list_raw_files(key)) + "')"
)
restr_graph.graph.add_node(raw_name, ft=raw_tbl, restr=raw_restr)

analysis_tbl = self._externals["analysis"]
analysis_name = analysis_tbl.full_table_name
analysis_restr = ( # filepaths have analysis subdir. regexp substrings
"filepath REGEXP '" + "|".join(self._list_analysis_files(key)) + "'"
) # regexp is slow, but we're only doing this once, and future-proof
restr_graph.graph.add_node(
analysis_name, ft=analysis_tbl, restr=analysis_restr
)

if raw_files := self._list_raw_files(key):
raw_tbl = self._externals["raw"]
raw_name = raw_tbl.full_table_name
raw_restr = "filepath in ('" + "','".join(raw_files) + "')"
restr_graph.graph.add_node(raw_name, ft=raw_tbl, restr=raw_restr)
restr_graph.visited.add(raw_name)

if analysis_files := self._list_analysis_files(key):
analysis_tbl = self._externals["analysis"]
analysis_name = analysis_tbl.full_table_name
# to avoid issues with analysis subdir, we use REGEXP
# this is slow, but we're only doing this once, and future-proof
analysis_restr = (
"filepath REGEXP '" + "|".join(analysis_files) + "'"
)
restr_graph.graph.add_node(
analysis_name, ft=analysis_tbl, restr=analysis_restr
)
restr_graph.visited.add(analysis_name)

restr_graph.visited.update({raw_name, analysis_name})

Expand Down
18 changes: 13 additions & 5 deletions src/spyglass/position/v1/position_dlc_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,16 +98,24 @@ def insert_entry(
dj.conn(), full_table_name=part_table.parents()[-1]
) & {"project_name": project_name}

if cls._test_mode: # temporary fix for #1105
project_path = table_query.fetch(limit=1)[0]
else:
project_path = table_query.fetch1("project_path")
n_found = len(table_query)
if n_found != 1:
logger.warning(
f"Found {len(table_query)} entries found for project "
+ f"{project_name}:\n{table_query}"
)

choice = "y"
if n_found > 1 and not cls._test_mode:
choice = dj.utils.user_choice("Use first entry?")[0]
if n_found == 0 or choice != "y":
return

part_table.insert1(
{
"dlc_model_name": dlc_model_name,
"project_name": project_name,
"project_path": project_path,
"project_path": table_query.fetch("project_path", limit=1)[0],
**key,
},
**kwargs,
Expand Down
2 changes: 0 additions & 2 deletions src/spyglass/position/v1/position_dlc_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ class DLCProject(SpyglassMixin, dj.Manual):
With ability to edit config, extract frames, label frames
"""

# Add more parameters as secondary keys...
# TODO: collapse params into blob dict
definition = """
project_name : varchar(100) # name of DLC project
---
Expand Down
14 changes: 11 additions & 3 deletions src/spyglass/utils/dj_helper_fn.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ def get_nwb_table(query_expression, tbl, attr_name, *attrs, **kwargs):
Function to get the absolute path to the NWB file.
"""
from spyglass.common.common_nwbfile import AnalysisNwbfile, Nwbfile
from spyglass.utils.dj_mixin import SpyglassMixin

kwargs["as_dict"] = True # force return as dictionary
attrs = attrs or query_expression.heading.names # if none, all
Expand All @@ -234,11 +235,18 @@ def get_nwb_table(query_expression, tbl, attr_name, *attrs, **kwargs):
}
file_name_str, file_path_fn = tbl_map[which]

# logging arg only if instanced table inherits Mixin
inst = ( # instancing may not be necessary
query_expression()
if isinstance(query_expression, type)
and issubclass(query_expression, dj.Table)
else query_expression
)
arg = dict(log_export=False) if isinstance(inst, SpyglassMixin) else dict()

# TODO: check that the query_expression restricts tbl - CBroz
nwb_files = (
query_expression.join(
tbl.proj(nwb2load_filepath=attr_name), log_export=False
)
query_expression.join(tbl.proj(nwb2load_filepath=attr_name), **arg)
).fetch(file_name_str)

# Disabled #1024
Expand Down
11 changes: 8 additions & 3 deletions src/spyglass/utils/dj_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,10 @@ def _nwb_table_tuple(self) -> tuple:

Used to determine fetch_nwb behavior. Also used in Merge.fetch_nwb.
Implemented as a cached_property to avoid circular imports."""
from spyglass.common.common_nwbfile import (
from spyglass.common.common_nwbfile import ( # noqa F401
AnalysisNwbfile,
Nwbfile,
) # noqa F401
)

table_dict = {
AnalysisNwbfile: "analysis_file_abs_path",
Expand Down Expand Up @@ -857,4 +857,9 @@ def delete(self, *args, **kwargs):
"""Delete master and part entries."""
restriction = self.restriction or True # for (tbl & restr).delete()

(self.master & restriction).delete(*args, **kwargs)
try: # try restriction on master
restricted = self.master & restriction
except DataJointError: # if error, assume restr of self
restricted = self & restriction

samuelbray32 marked this conversation as resolved.
Show resolved Hide resolved
restricted.delete(*args, **kwargs)
Loading