• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Hekxsler / pudding / 18468262725

13 Oct 2025 02:00PM UTC coverage: 85.586% (+2.8%) from 82.779%
18468262725

push

github

web-flow
[writer]: fix value being None as a string

1045 of 1221 relevant lines covered (85.59%)

0.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.74
pudding/processor/context.py
1
"""Module defining context class."""
2

3
import re
1✔
4

5
from ..datatypes.string import String
1✔
6
from ..reader.reader import Reader
1✔
7
from ..writer.writer import Writer
1✔
8
from .grammar import Grammar
1✔
9
from .triggers import TriggerQueue
1✔
10

11
STRING_VAR_RE = r"([^\d]?\$(\d+)[^\$]?)"
1✔
12
# match chars before and after to not match $1 and $10 when replacing $1
13

14

15
class Context:
1✔
16
    """Class containing context for the processor.
17

18
    :var grammars: Grammars defined in the syntax.
19
    :var queue: Queue for triggers created by enqueued statements.
20
    :var variables: Variables defined in the syntax.
21
    """
22

23
    def __init__(self, content: str, writer_cls: type[Writer]) -> None:
1✔
24
        """Init for Context class.
25

26
        :param content: Content of the file to convert.
27
        :param writer_cls: Writer class for generating output.
28
        """
29
        self.grammars: dict[str, Grammar] = {}
1✔
30
        self.queue: TriggerQueue = TriggerQueue()
1✔
31
        self.variables: dict[str, re.Pattern[str]] = {}
1✔
32
        self.reader = Reader(content)
1✔
33
        self.writer = writer_cls()
1✔
34

35
    def get_grammar(self, name: str) -> Grammar:
1✔
36
        """Get a grammar by name.
37

38
        :param name: Name of the grammar to retrieve.
39
        :raises SyntaxError: If grammar is not defined.
40
        """
41
        grammar = self.grammars.get(name)
1✔
42
        if not grammar:
1✔
43
            raise SyntaxError(f'Grammar "{name}" is not defined.')
×
44
        return grammar
1✔
45

46
    def get_var(self, name: str) -> re.Pattern[str]:
1✔
47
        """Get a variable by name.
48

49
        :param name: Name of the variable to retrieve.
50
        :raises NameError: If variable is not defined.
51
        """
52
        value = self.variables.get(name)
1✔
53
        if not value:
1✔
54
            raise NameError(f'Variable "{name}" is not defined.')
×
55
        return value
1✔
56

57
    def replace_string_vars(self, string: String) -> str:
1✔
58
        """Replace variables in a string with the last matched values.
59

60
        :param string: String to replace vars in.
61
        :param context: The current context.
62
        :returns: The string with replaced values.
63
        """
64
        string_vars = re.findall(STRING_VAR_RE, string.value)
1✔
65
        if len(string_vars) == 0:
1✔
66
            return string.value
1✔
67
        if self.reader.last_match is None:
1✔
68
            raise RuntimeError(
×
69
                "Can not replace variables, because no expression matched yet."
70
            )
71
        new_string = string.value
1✔
72
        matches = self.reader.last_match.groups()
1✔
73
        for replace, i in string_vars:
1✔
74
            assert isinstance(replace, str)
1✔
75
            if int(i) > len(matches):
1✔
76
                raise IndexError(f"Not enough matches to replace variable '${i}'.")
×
77
            value = replace.replace(f"${i}", matches[int(i)])
1✔
78
            new_string = re.sub(re.escape(replace), value, new_string)
1✔
79
        return new_string
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc