Skip to content

searchby

This module contains the classes that represent Obsidian search strategies.

A search strategy define how Filter are applied to Vault.

A generic interface for search strategies is provided by the SearchBy class.

SearchBy

Bases: Protocol

Interface for search strategies.

Mechanism for the search.

It's used by the search method.

Parameters:

  • notes (list[Note]) –

    A list of notes to search through.

  • field (Field) –

    The field to search for.

Returns:

  • list[Note]

    A list of notes that match the field value.

Source code in pyobsidian/searchby.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
def __search(self, notes: list[Note], field: Field) -> list[Note]:
    """Mechanism for the search.

    It's used by the `search` method.

    Parameters
    ----------
    notes : list[Note]
        A list of notes to search through.
    field : Field
        The field to search for.

    Returns
    -------
    list[Note]
        A list of notes that match the field value.
    """
    ...

condition(note: Note, field: Field) -> bool

Function that implements the condition of the search.

Parameters:

  • note (Note) –

    The note to be checked.

  • field (Field) –

    The field to be checked.

Returns:

  • bool

    True if the condition is met, False otherwise.

Source code in pyobsidian/searchby.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def condition(self: Self, note: Note, field: Field) -> bool:
    """Function that implements the condition of the search.

    Parameters
    ----------
    note : Note
        The note to be checked.
    field : Field
        The field to be checked.

    Returns
    -------
    bool
        True if the condition is met, False otherwise.
    """
    ...

convert_field_value_to_list(value: FieldValue) -> FieldValue staticmethod

Convert the given field value to a list if it's a string.

Parameters:

  • value (FieldValue) –

    The field value to be converted.

Returns:

  • list[str]

    A list of strings.

Source code in pyobsidian/searchby.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
@staticmethod
def convert_field_value_to_list(value: FieldValue) -> FieldValue:
    """Convert the given field value to a list if it's a string.

    Parameters
    ----------
    value : FieldValue
        The field value to be converted.

    Returns
    -------
    list[str]
        A list of strings.
    """
    ...

is_valid_value(value: FieldValue) -> bool

Check if the given value is a valid field value.

Parameters:

  • value (FieldValue) –

    The value to be checked.

Returns:

  • bool

    True if the value is valid, False otherwise.

Raises:

  • ValueError

    If the value is not a string or a list.

Source code in pyobsidian/searchby.py
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
def is_valid_value(self: Self, value: FieldValue) -> bool:
    """Check if the given value is a valid field value.

    Parameters
    ----------
    value : FieldValue
        The value to be checked.

    Returns
    -------
    bool
        True if the value is valid, False otherwise.

    Raises
    ------
    ValueError
        If the value is not a string or a list.
    """
    ...

search(notes: list[Note], field: Field) -> list[Note]

Search for notes that match the given field value.

The implementation is given by the __search method.

Parameters:

  • notes (list[Note]) –

    A list of notes to search through.

  • field (Field) –

    The field to search for.

Returns:

  • list[Note]

    A list of notes that match the field value.

Source code in pyobsidian/searchby.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
def search(self: Self, notes: list[Note], field: Field,) -> list[Note]:
    """Search for notes that match the given field value.

    The implementation is given by the `__search` method.

    Parameters
    ----------
    notes : list[Note]
        A list of notes to search through.
    field : Field
        The field to search for.

    Returns
    -------
    list[Note]
        A list of notes that match the field value.
    """
    ...

SearchByContent

Bases: SearchByDefault

Search by note properties content

SearchByDate

Bases: SearchByDefault

Search by note properties date

Date search mechanism.

In this mechanism, same logic as the SearchByDefault class is used. However, the field values ​​are not traversed as the list is passed to the condition.

A set is used to remove potential duplicates.

Source code in pyobsidian/searchby.py
257
258
259
260
261
262
263
264
265
266
267
268
269
def __search(self, notes: list[Note], field: Field) -> list[Note]:
    """Date search mechanism.

    In this mechanism, same logic as the `SearchByDefault` class is used.
    However, the field values ​​are not traversed as the list is passed to the `condition`.

    A set is used to remove potential duplicates.
    """
    filtered_notes = []
    for note in notes:
        if self.condition(note, field):
            filtered_notes.append(note)
    return list(set(filtered_notes))

condition(note: Note, field: Field) -> bool

Condition check if note date propertie is between start and end date.

First element from field value is the date propertie. Second and third elements from field value are start and end date respectively.

Parameters:

  • note (Note) –

    The note to be checked.

  • field (Field) –

    The field to be checked.

Returns:

  • bool

    True if the note date propertie is between start and end date, False otherwise.

Source code in pyobsidian/searchby.py
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
def condition(self: Self, note: Note, field: Field) -> bool:
    """Condition check if note date propertie is between start and end date.

    First element from field value is the date propertie.
    Second and third elements from field value are start and end date respectively.

    Parameters
    ----------
    note : Note
        The note to be checked.
    field : Field
        The field to be checked.

    Returns
    -------
    bool
        True if the note date propertie is between start and end date, False otherwise.
    """
    value = field.value
    date_propertie = value[0]
    start_date = datetime.strptime(value[1], '%Y-%m-%d')
    end_date = datetime.strptime(value[2], '%Y-%m-%d')
    note_date = getattr(note.properties, date_propertie)
    return note_date >= start_date and note_date <= end_date

is_valid_value(value: FieldValue) -> bool

Check if the given value is a valid date field value.

Parameters:

  • value (FieldValue) –

    The value to be checked.

Returns:

  • bool

    True if the value is valid, False otherwise.

Raises:

  • ValueError

    If the value is not a list with 3 elements

Source code in pyobsidian/searchby.py
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
def is_valid_value(self: Self, value: FieldValue) -> bool:
    """Check if the given value is a valid date field value.

    Parameters
    ----------
    value : FieldValue
        The value to be checked.

    Returns
    -------
    bool
        True if the value is valid, False otherwise.

    Raises
    ------
    ValueError
        If the value is not a list with 3 elements
    """
    if not isinstance(value, list):
        raise ValueError(f'`{value}` must be a list')
    if len(value) != 3:
        raise ValueError(f'`{value}` must be a list with 3 elements: [\'date_propertie\', \'start_date\', \'end_date\']')
    if isinstance(value, list) and len(value) == 3:
        return True
    raise ValueError(f'`{value}` must be a list with 3 elements: [\'date_propertie\', \'start_date\', \'end_date\']')

SearchByDefault

Bases: SearchBy

Default search strategy. Acts as a template for other search strategies.

Default search mechanism.

In this mechanism, each value of the field is checked against the notes. If the value is found in the note, it is added to the filtered notes list.

A set is used to remove potential duplicates.

Source code in pyobsidian/searchby.py
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
def __search(self, notes: list[Note], field: Field) -> list[Note]:
    """Default search mechanism.

    In this mechanism, each value of the field is checked against the
    notes. If the value is found in the note, it is added to the
    filtered notes list.

    A set is used to remove potential duplicates.
    """
    values = self.convert_field_value_to_list(field.value)
    filtered_notes = []
    for value in values:
        cur_field = Field(field.key, value, field.occurrence)
        for note in notes:
            if self.condition(note, cur_field):
                filtered_notes.append(note)
    return list(set(filtered_notes))

condition(note: Note, field: Field) -> bool

Default condition check if field value is in the note properties.

Source code in pyobsidian/searchby.py
155
156
157
def condition(self: Self, note: Note, field: Field) -> bool:
    """Default condition check if field value is in the note properties."""
    return field.value in getattr(note.properties, field.key)

is_valid_value(value: FieldValue) -> bool

Default check if a string or a list. If not, raise an error.

Returns:

  • bool

    True if the value is valid, False otherwise.

Raises:

  • ValueError

    If the value is not a string or a list.

Source code in pyobsidian/searchby.py
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
def is_valid_value(self: Self, value: FieldValue) -> bool:
    """Default check if a string or a list. If not, raise an error.

    Returns
    -------
    bool
        True if the value is valid, False otherwise.

    Raises
    ------
    ValueError
        If the value is not a string or a list.
    """
    if not isinstance(value, str) and not isinstance(value, list):
        raise ValueError(f'`{value}` must be a string or a list')
    return True

SearchByFolder

Bases: SearchByDefault

Search by note properties folder

condition(note: Note, field: Field) -> bool

Condition check if any value of field value is in the note properties folder.

Source code in pyobsidian/searchby.py
176
177
178
179
180
def condition(self: Self, note: Note, field: Field) -> bool:
    """Condition check if any value of field value is in the note properties folder."""
    norm_value = os.path.normpath(str(field.value))
    attrs = getattr(note.properties, field.key)
    return any([norm_value in attr for attr in attrs])

SearchByOccurrence

Bases: SearchByDefault

Occurrence search strategy.

Acts as a template for search strategies that need to check if the field value is in the note properties that occurs inline, yaml or both.

condition(note: Note, field: Field) -> bool

Condition check if any value of field value is in the note properties that occurs inline, yaml or both.

Use the same search method as the SearchByDefault class.

Source code in pyobsidian/searchby.py
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
def condition(self: Self, note: Note, field: Field) -> bool:
    """Condition check if any value of field value is in the note properties that occurs inline, yaml or both.

    Use the same `search` method as the `SearchByDefault` class.
    """
    inline = getattr(note.properties, field.key)['inline']
    yaml = getattr(note.properties, field.key)['yaml']
    check_inline = field.value in inline if inline else False
    check_yaml = field.value in yaml if yaml else False
    match field.occurrence:
        case 'inline':
            return check_inline
        case 'yaml':
            return check_yaml
        case 'file':
            return check_inline or check_yaml
        case _:
            raise ValueError(f'`{field.occurrence}` is not a valid tag occurrence')

SearchByRegex

Bases: SearchByDefault

Search by regex in note properties content

condition(note: Note, field: Field) -> bool

Condition check regex pattern matches in note properties content.

Source code in pyobsidian/searchby.py
187
188
189
190
def condition(self: Self, note: Note, field: Field) -> bool:
    """Condition check regex pattern matches in note properties content."""
    attr = getattr(note.properties, 'content')
    return any(re.findall(str(field.value), attr))

SearchByTag

Bases: SearchByOccurrence

Search by note properties tag inline, yaml or both

get_search_strategies() -> dict[FieldKey, SearchBy]

Define a dict of search strategies

Returns:

  • dict[FieldKey, SearchBy]

    The dict of search strategies

Source code in pyobsidian/searchby.py
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
def get_search_strategies() -> dict[FieldKey, SearchBy]:
    """Define a dict of search strategies

    Returns
    -------
    dict[FieldKey, SearchBy]
        The dict of search strategies
    """
    return {
        'folder': SearchByFolder(),
        'content': SearchByContent(),
        'regex': SearchByRegex(),
        'date': SearchByDate(),
        'tag': SearchByTag(),
        'related_note': SearchByRelatedNote()
    }