Skip to content

common

Common objects

FILTER_TYPE module-attribute #

FILTER_TYPE = Union[F, FilterList, ComplexFilter]

OP module-attribute #

OP = {'eq': '==', 'neq': '!=', 'lt': '<', 'le': '<=', 'gt': '>', 'ge': '>=', 'or': '&', 'in': 'in', 'contain': 'contain', 'like': 'like', 'not_like': '!like', 'glob': 'glob', 'not_glob': '!glob'}

ComplexFilter #

ComplexFilter(a: Union[ComplexFilter, FilterList, F], op: Literal['||', '&&'], b: Union[ComplexFilter, FilterList, F])

Complex handling of filters and their operator

Source code in pyfortinet/fmg_api/common.py
def __init__(
    self,
    a: Union["ComplexFilter", FilterList, F],
    op: Literal["||", "&&"],
    b: Union["ComplexFilter", FilterList, F],
):
    self.a = a
    self.op = op
    self.b = b

generate #

generate() -> list

Generate API filter output

Source code in pyfortinet/fmg_api/common.py
def generate(self) -> list:
    """Generate API filter output"""
    out = [self.a.generate(), self.op, self.b.generate()]
    return out

F #

F(**kwargs)

Filter class that allows us to define a single filter for an object

Argument format is {field}={value} or {field}__{operator}={value} Only one argument can be passed!

Filter object can be used at FMG.get method

Attributes:

Name Type Description
negate bool

If true the filter is negated

source str

The source is the API attribute we are looking at

op str

The operator for the search

targets str

The target is the value we are searching for

Source code in pyfortinet/fmg_api/common.py
def __init__(self, **kwargs):
    """Filter initialization"""
    if len(kwargs) > 1:
        raise ValueError(f"F only accepts one filter condition at a time!")
    for key, value in kwargs.items():
        if "__" in key:
            self.source, self.op = key.split("__")
            if self.op not in OP:
                raise ValueError(f"Unknown operation: '{self.op}' !")
            self.op = OP[self.op]
        else:
            self.source = key
            self.op = "=="
        self.targets = value

generate #

generate() -> List[str]

Generate API filter list

Source code in pyfortinet/fmg_api/common.py
def generate(self) -> List[str]:
    """Generate API filter list"""
    out = []
    if self.negate:
        out.append("!")
    out.append(self.source)
    out.append(self.op)
    if isinstance(self.targets, list):
        out.extend(self.targets)
    else:
        out.append(self.targets)
    return out

FilterList #

FilterList(*members: Union[F, FilterList])

List of F objects

Source code in pyfortinet/fmg_api/common.py
def __init__(self, *members: Union[F, "FilterList"]):
    self.members = []
    for member in members:
        self + member

generate #

generate() -> List[List[str]]

Generate API filter output

Source code in pyfortinet/fmg_api/common.py
def generate(self) -> List[List[str]]:
    """Generate API filter output"""
    return [member.generate() for member in self.members]

Scope #

Specify scope for an object

Attributes:

Name Type Description
name str

Scope name (e.g. firewall name or group name)

vdom str

VDOM if applicable

text_to_filter #

text_to_filter(text: str) -> FILTER_TYPE

Text to filter object

Format of the text follows the OP definition! This is a simple text to filter object converter. It does not support more complex logic. Simple field comparisons with and/or and , operators are supported. , means a simple or between same type fields.

structure::

fname fop fvalue OP fname fop fvalue OP ...
----------------    ----------------
    F token              F token

Examples:

simple F filter

>>> text_to_filter('name like host_%').generate()
['name', 'like', 'host_%']

inversing

>>> text_to_filter('~name like host_%').generate()
['!', 'name', 'like', 'host_%']

simple or function

>>> text_to_filter('name eq host_1, name eq host_2').generate()
[['name', '==', 'host_1'], ['name', '==', 'host_2']]

more complex filter

>>> text_to_filter('name eq host_1 and conf_status eq insync').generate()
[['name', '==', 'host_1'], '&&', ['conf_status', '==', 'insync']]

Parameters:

Name Type Description Default
text str

Text to parse

required

Returns:

Name Type Description
FILTER_TYPE FILTER_TYPE

Filter object which can be used in FMG.get calls

Raises: ValueError: text cannot be parsed

Source code in pyfortinet/fmg_api/common.py
def text_to_filter(text: str) -> FILTER_TYPE:
    """Text to filter object

    Format of the text follows the ``OP`` definition!
    This is a simple text to filter object converter. It does not support more complex logic.
    Simple field comparisons with `and/or and ,` operators are supported. `,` means a simple `or` between same
    type fields.

    structure::

        fname fop fvalue OP fname fop fvalue OP ...
        ----------------    ----------------
            F token              F token

    Examples:
        simple F filter

        >>> text_to_filter('name like host_%').generate()
        ['name', 'like', 'host_%']

        inversing

        >>> text_to_filter('~name like host_%').generate()
        ['!', 'name', 'like', 'host_%']

        simple or function

        >>> text_to_filter('name eq host_1, name eq host_2').generate()
        [['name', '==', 'host_1'], ['name', '==', 'host_2']]

        more complex filter

        >>> text_to_filter('name eq host_1 and conf_status eq insync').generate()
        [['name', '==', 'host_1'], '&&', ['conf_status', '==', 'insync']]

    Args:
        text (str): Text to parse

    Returns:
        FILTER_TYPE: Filter object which can be used in FMG.get calls

     Raises:
         ValueError: text cannot be parsed
    """
    text = text.strip()
    while text:
        # search F tokens
        f_match = re.match(
            rf'(?P<negate>~)?\s*(?P<fname>\w+)\s+(?P<fop>{"|".join(OP.keys())})\s+(?P<fvalue>\S+)(?<![,|&])', text
        )
        if f_match:
            kwargs = {f"{f_match.group('fname')}__{f_match.group('fop')}": f_match.group("fvalue")}
            if f_match.group("negate"):
                f_token = ~F(**kwargs)
            else:
                f_token = F(**kwargs)
        else:
            raise ValueError(f"Couldn't parse '{text}'!")
        text = text[f_match.end() :].strip()
        if not text:
            return f_token
        # search list or complex filter ops
        op_match = re.match(rf"(?P<op>and|or|,)\s+", text)
        if op_match:
            op = {"and": "&&", "or": "||", ",": ","}.get(op_match.group("op"))
        else:
            raise ValueError(f"Couldn't parse '{text}'!")
        text = text[op_match.end() :].strip()
        f_token2 = text_to_filter(text)
        if op == ",":
            return FilterList(f_token, f_token2)
        else:
            # noinspection PyTypeChecker, PydanticTypeChecker
            return ComplexFilter(f_token, op, f_token2)