Skip to content

common

Functions:

index_after_newline

index_after_newline(text: str, position: int) -> int

Return new position with the newline eaten at the input position

Source code in ipsl_common/modipsl/common.py
 7
 8
 9
10
11
12
def index_after_newline(text: str, position: int) -> int:
    """Return new position with the newline eaten at the input position"""
    # There are no newlines at the end!
    if position == len(text):
        return position
    return position + 1 if text[position] == "\n" else position

inject_value_position

inject_value_position(func: Callable) -> Callable

Retrieve in-text position of values from their token(s).

This decorator works with grammar generated methods of the lark.Transformer. It works well on scalar (e.g. 1, 3.14, True) and compound (e.g. (1, 2, 3)) values, because those are represented using only lark.Tokens, each with a start_pos/end_pos attributes. The decorator converts the normal parsing method into the one that takes those position attributes and transform the parsed value to a dictionary comining the original value with its positions.

Parameters:

  • func

    (Callable) –

    lark.Transformer based method to decorate

Returns:

  • Callable ( Callable ) –

    decorated method returning dictionary with the parsed value and its positions in the text

Source code in ipsl_common/modipsl/common.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
def inject_value_position(func: Callable) -> Callable:
    """Retrieve in-text position of values from their token(s).

    This decorator works with grammar generated methods of the lark.Transformer.
    It works well on scalar (e.g. `1`, `3.14`, `True`) and compound
    (e.g. `(1, 2, 3)`) values, because those are represented using only
    lark.Tokens, each with a start_pos/end_pos attributes.
    The decorator converts the normal parsing method into the one
    that takes those position attributes and transform the parsed value to
    a dictionary comining the original value with its positions.

    Args:
        func: lark.Transformer based method to decorate

    Returns:
        Callable: decorated method returning dictionary with the parsed value and its positions in the text
    """

    @functools.wraps(func)
    def wrapper_decorator(self, tokens):
        # Get scalar value
        value = func(self, tokens)
        if self._include_positions:
            # Retrive position from token(s)
            return {
                "value": value,
                "start_pos": tokens[0].start_pos,
                "end_pos": tokens[-1].end_pos,
            }
        else:
            return value

    return wrapper_decorator

is_empty_rule_branch

is_empty_rule_branch(
    entity: Any, rule_name: str | None = None
) -> bool

Check if entity is an empty rule branch of an AST with an empty Token.

Such empty branch is created when an optional sub-rule (e.g. rule: optional? required) is not present.

Parameters:

  • entity

    (Any) –

    potential empty rule branch to check

  • rule_name

    (str | None, default: None ) –

    optional grammar rule name to validate in the empty rule branch

Returns:

  • bool ( bool ) –

    True, if entity is an empty rule branch

Source code in ipsl_common/modipsl/common.py
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
def is_empty_rule_branch(entity: Any, rule_name: str | None = None) -> bool:
    """Check if entity is an empty rule branch of an AST with an empty Token.

    Such empty branch is created when an optional sub-rule
    (e.g. `rule: optional? required`) is not present.

    Args:
        entity: potential empty rule branch to check
        rule_name: optional grammar rule name to validate in the empty rule branch

    Returns:
        bool: True, if entity is an empty rule branch
    """
    if not isinstance(entity, Tree):
        return False
    rule_check = (
        entity.data == Token("RULE", rule_name) if rule_name is not None else True
    )
    return (
        isinstance(entity.data, Token)
        and not entity.children
        # Also, check if rule name matches if passed as an argument
        and rule_check
    )

retrieve_values

retrieve_values(obj: Any) -> dict | list

Retrieve only values from a nested structure with position attributes.

The .def/.card decoding with inserting value/key/section positions convert those files into Python dictionaries which, apart from values, contains additional keys such as start_pos, end_pos, key_start_pos, section_start_pos and section_end_pos. Those keys encode the start/end positions of various elements of those file formats. This function removes them and it keeps only the original values from the files.

Example input dictionary:

{
    'section': {
        'b': {
            'value': 2,
            'start_pos': 16,
            'end_pos': 17,
            'key_start_pos': 14
        }
    }
}

And the result:

{
    'section': {
        'b': 2
    }
}

Parameters:

  • obj

    (Any) –

    object with values to retrive

Returns:

  • dict ( dict | list ) –

    a new object with only values

Source code in ipsl_common/modipsl/common.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
def retrieve_values(obj: Any) -> dict | list:
    """Retrieve only values from a nested structure with position attributes.

    The *.def/*.card decoding with inserting value/key/section positions
    convert those files into Python dictionaries which, apart from values,
    contains additional keys such as `start_pos`, `end_pos`, `key_start_pos`,
    `section_start_pos` and `section_end_pos`. Those keys encode the start/end
    positions of various elements of those file formats. This function removes
    them and it keeps only the original values from the files.

    Example input dictionary:

        {
            'section': {
                'b': {
                    'value': 2,
                    'start_pos': 16,
                    'end_pos': 17,
                    'key_start_pos': 14
                }
            }
        }

    And the result:

        {
            'section': {
                'b': 2
            }
        }

    Args:
        obj: object with values to retrive

    Returns:
        dict: a new object with only values
    """
    if isinstance(obj, dict):
        if "value" in obj:
            return retrieve_values(obj["value"])
        return {k: retrieve_values(v) for k, v in obj.items()}
    elif isinstance(obj, list):
        return [retrieve_values(item) for item in obj]
    return obj