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

Workbench: Cache cotype column for determining column to validate taxon with #6332

Draft
wants to merge 5 commits into
base: production
Choose a base branch
from
Draft
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
2 changes: 2 additions & 0 deletions specifyweb/workbench/upload/scope_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class ScopingCache(TypedDict):
# or cotypes but want to reuse as much as other field based info
fields: Dict[Tuple[Any, str, str], Optional[UIFormatter]]
date_format: Optional[str]
cotype_column: Optional[str]

class ScopeContext(object):
cache: ScopingCache
Expand All @@ -23,6 +24,7 @@ def __init__(self):
self.cache['cotypes'] = {}
self.cache['date_format'] = None
self.cache['fields'] = {}
self.cache['cotype_column'] = None

def set_is_variable(self):
# We "discover" whether the scoping is variable across the rows.
Expand Down
8 changes: 6 additions & 2 deletions specifyweb/workbench/upload/scoping.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ def extend_columnoptions(
None if ui_formatter is None else ui_formatter.apply_scope(collection)
)

if tablename.lower() == "collectionobjecttype" and fieldname.lower() == "name":
context.cache['cotype_column'] = colopts.column

# REFACTOR: Make context always required and simply
date_format = context.cache['date_format']
date_format = get_date_format() if date_format is None else date_format
Expand Down Expand Up @@ -345,7 +348,7 @@ def set_order_number(
return tmr._replace(strong_ignore=[*tmr.strong_ignore, *to_ignore])


def apply_scoping_to_treerecord(tr: TreeRecord, collection) -> ScopedTreeRecord:
def apply_scoping_to_treerecord(tr: TreeRecord, collection, context: Optional[ScopeContext] = None) -> ScopedTreeRecord:
table = datamodel.get_table_strict(tr.name)

treedef = get_default_treedef(table, collection)
Expand Down Expand Up @@ -390,5 +393,6 @@ def apply_scoping_to_treerecord(tr: TreeRecord, collection) -> ScopedTreeRecord:
root=root[0] if root else None,
disambiguation={},
batch_edit_pack=None,
scoped_cotypes=scoped_cotypes
scoped_cotypes=scoped_cotypes,
cotype_column=context.cache['cotype_column'] if context else None
)
21 changes: 8 additions & 13 deletions specifyweb/workbench/upload/treerecord.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def apply_scoping(
) -> "ScopedTreeRecord":
from .scoping import apply_scoping_to_treerecord as apply_scoping

return apply_scoping(self, collection)
return apply_scoping(self, collection, context)

def get_cols(self) -> Set[str]:
return {col.column for r in self.ranks.values() for col in r.values() if hasattr(col, 'column')}
Expand Down Expand Up @@ -170,6 +170,7 @@ class ScopedTreeRecord(NamedTuple):
disambiguation: Dict[str, int]
batch_edit_pack: Optional[Dict[str, Any]]
scoped_cotypes: Any
cotype_column: Optional[str]

def disambiguate(self, disambiguation: DA) -> "ScopedTreeRecord":
return (
Expand Down Expand Up @@ -317,27 +318,21 @@ def _handle_multiple_or_no_treedefs(self,

# Ensure cotype has same taxontreedef for ranks in row
def _validate_trees_with_cotype(self, row: Row, treedefs_in_row: Set[int]):
if self.name.lower() != "taxon":
if self.name.lower() != "taxon" or self.cotype_column is None:
return None

# TODO: Need a better way to do this
# Find a way to send cotype column when ScopedTreeRecord instance is created?
COL_NAMES = ["Type", "Collection Object Type"]
def find_cotype_in_row(row: Row):
for col_name, value in row.items():
if col_name in COL_NAMES:
return col_name, value
if isinstance(self.cotype_column, str) and self.cotype_column in row:
return row[self.cotype_column]

return None

def get_cotype_tree_def(cotype_name: str):
cotypes = self.scoped_cotypes.filter(name=cotype_name)
return cotypes[0].taxontreedef.id if len(cotypes) > 0 else None

cotype = find_cotype_in_row(row)
if not cotype: return None

cotype_column, cotype_value = cotype
cotype_value = find_cotype_in_row(row)
if not cotype_value: return None

cotype_treedef_id = get_cotype_tree_def(cotype_value)
if not cotype_treedef_id: return None
Expand All @@ -347,7 +342,7 @@ def get_cotype_tree_def(cotype_name: str):
if len(treedefs_in_row) > 0 and cotype_treedef_id == list(treedefs_in_row)[0]:
return None

return self, WorkBenchParseFailure('Invalid type for selected tree rank(s)', {}, cotype_column)
return self, WorkBenchParseFailure('Invalid type for selected tree rank(s)', {}, self.cotype_column)

def bind(
self,
Expand Down
Loading