diff --git a/metacatalog/api/add.py b/metacatalog/api/add.py index 3e7ec175..f536c4a0 100644 --- a/metacatalog/api/add.py +++ b/metacatalog/api/add.py @@ -121,7 +121,7 @@ def add_unit(session: 'Session', name: str, symbol: str, si: str = None) -> mode return add_record(session=session, tablename='units', **attrs) -def add_variable(session: 'Session', name: str, symbol: str, column_names: List[str], unit: Union[int, str]) -> models.Variable: +def add_variable(session: 'Session', name: str, symbol: str, column_names: List[str], unit: Union[int, str], keyword: Union[int, str] = None) -> models.Variable: r""" Add a new variable to the database. @@ -142,6 +142,12 @@ def add_variable(session: 'Session', name: str, symbol: str, column_names: List[ unit : int, str Either the id or **full** name of the unit to be linked to this variable. + keyword: int, str + .. versionadded:: 0.8.4 + Either the id or **full** path of the keyword to be + linked to this variable. + It is strongly recommended to add a keyword from a controlled thesaurus to a + newly created variable to improve the findability of the variable. Returns ------- @@ -159,9 +165,20 @@ def add_variable(session: 'Session', name: str, symbol: str, column_names: List[ unit = api.find_unit(session=session,name=unit, return_iterator=True).first() else: raise AttributeError('unit has to be of type integer or string.') - + attrs['unit_id'] = unit.id + # get the keyword + if keyword: + if isinstance(keyword, int): + keyword = api.find_keyword(session=session, id=keyword, return_iterator=True).one() + elif isinstance(keyword, str): + keyword = api.find_keyword(session=session, full_path=keyword, return_iterator=True).first() + else: + raise AttributeError('keyword has to be of type integer or string.') + + attrs['keyword_id'] = keyword.id + # add the variable return add_record(session=session, tablename='variables', **attrs) diff --git a/metacatalog/api/find.py b/metacatalog/api/find.py index 35346e1f..4f204799 100644 --- a/metacatalog/api/find.py +++ b/metacatalog/api/find.py @@ -83,7 +83,7 @@ def _match(column_instance: InstrumentedAttribute, compare_value: str, invert: b def find_keyword(return_iterator: Literal[False] = False) -> List['Keyword']: ... @overload def find_keyword(return_iterator: Literal[True] = False) -> 'Query': ... -def find_keyword(session: 'Session', id: Optional[int] = None, uuid: Optional[str] = None, value: Optional[str] = None, thesaurus_name: Optional[str] = None, return_iterator: bool = False) -> List['Keyword'] | 'Query': +def find_keyword(session: 'Session', id: Optional[int] = None, uuid: Optional[str] = None, value: Optional[str] = None, full_path: Optional[str] = None, thesaurus_name: Optional[str] = None, return_iterator: bool = False) -> List['Keyword'] | 'Query': """ Return one or many keyword entries from the database on exact matches. @@ -103,6 +103,10 @@ def find_keyword(session: 'Session', id: Optional[int] = None, uuid: Optional[st value : str Value of the requested keyword(s). Multiple record return is possible. + full_path : str + .. versionadded:: 0.8.4 + + Full path of the requested keyword. thesaurus_name : str .. versionadded:: 0.1.10 @@ -133,6 +137,8 @@ def find_keyword(session: 'Session', id: Optional[int] = None, uuid: Optional[st # add needed filter if id is not None: query = query.filter(models.Keyword.id==id) + if full_path is not None: + query = query.filter(_match(models.Keyword.full_path, full_path)) if value is not None: query = query.filter(_match(models.Keyword.value, value)) if thesaurus_name is not None: diff --git a/metacatalog/test/test_api_add_find.py b/metacatalog/test/test_api_add_find.py index 824232d0..375f6172 100644 --- a/metacatalog/test/test_api_add_find.py +++ b/metacatalog/test/test_api_add_find.py @@ -185,6 +185,7 @@ def check_composite_raises_error(session): return "has to be of type 'Project'" in str(excinfo.value) + def find_by_project(session): dummies = api.find_group(session, title="Dumm%")[0] # create a project @@ -328,6 +329,31 @@ def mutate_details(session): return True +def add_variable(session): + """ + Check add variable and also add a unit. + + """ + # add unit + unit = api.add_unit(session, name='best_unit', symbol='bu', si='kg*m*s*1') + + # add variable + variable = api.add_variable(session, name='best_variable', symbol='bv', unit=unit.id, column_names=['best_variable'], + keyword='EARTH SCIENCE > * > ATMOSPHERIC/OCEAN INDICATORS > * > BIVARIATE ENSO TIMESERIES INDEX > BEST') + + # find unit and variable + find_unit = api.find_unit(session, name='best_unit')[0] + find_variable = api.find_variable(session, name='best_variable')[0] + + # assert + assert find_unit.symbol == 'bu' + assert find_variable.symbol == 'bv' + assert find_variable.unit.symbol == 'bu' + assert find_variable.keyword.full_path == 'EARTH SCIENCE > CLIMATE INDICATORS > ATMOSPHERIC/OCEAN INDICATORS > TELECONNECTIONS > BIVARIATE ENSO TIMESERIES INDEX > BEST' + + return True + + @pytest.mark.depends(on=['db_init'], name='add_find') def test_add_and_find(): """ @@ -354,3 +380,4 @@ def test_add_and_find(): assert check_get_by_uuid(session) assert find_by_author(session) assert check_find_person(session) + assert add_variable(session)