Skip to content

regex

Full documentation pages are generated for docstring reference only and may contain symbols imported from other modules. Imported symbols are not distinguished from locally defined symbols and will appear in any module that they are imported into. For better information on where symbols should be imported from, review the sourcecode on the github.

FoSpy.parsing.regex

BLOCK_HEADER module-attribute

BLOCK_HEADER = build_block_header_regex(
    SYNTAX["block_header"]
)

CALC_COMMENT_LINE module-attribute

CALC_COMMENT_LINE = build_calc_comment_regex(
    SYNTAX["calc_comment"]
)

COMMENT_LINE module-attribute

COMMENT_LINE = build_comment_regex(SYNTAX['comment'])

EMBEDDED_END module-attribute

EMBEDDED_END = build_embedded_end_regex(SYNTAX['embedded'])

EMBEDDED_START module-attribute

EMBEDDED_START = build_embedded_start_regex(
    SYNTAX["embedded"]
)

KEY_VALUE module-attribute

KEY_VALUE = build_key_value_regex(SYNTAX['key_value'])

LOOP_KEY module-attribute

LOOP_KEY = build_loop_key_regex(SYNTAX['key_value'])

NESTED_START module-attribute

NESTED_START = build_nested_start_regex(SYNTAX['nested'])

SYNTAX module-attribute

SYNTAX = {
    "block_header": {
        "single": {"open": "[", "close": "]"},
        "list": {"open": "[[", "close": "]]"},
    },
    "nested": {"open": "[", "close": "]"},
    "embedded": {
        "open": "{{{",
        "close": "END FOS EMBED }}}",
        "prefix": "#",
    },
    "key_value": {
        "delimiter": ":",
        "require_value": True,
        "prefix": False,
    },
    "comment": {"prefix": "//", "allow_leading_ws": True},
    "calc_comment": {
        "prefix": "!",
        "allow_leading_ws": True,
    },
    "indent_size": 4,
}

_debug module-attribute

_debug = Debug()

Debug

Source code in FoSpy/_debug.py
class Debug:
    def __init__(self):
        self.on = False

        frame = inspect.currentframe().f_back
        self.module_name = frame.f_globals.get("__name__", "<unknown>")
        self.label = f"|(Debug message from {self.module_name})"
        self.label_width = len(self.label)

    def _get_text_width(self, module=None):
        if module:
            label = f"|(Debug message from {module} via {self.module_name})"
            label_width = len(label)
        else:
            label = self.label
            label_width = self.label_width

        text_width = DEBUG_WIDTH - label_width
        return text_width, label, label_width


    def msg(self,msg, module=None):
        if not self.on:
            return

        text_width, label, label_width = self._get_text_width(module)

        wrapped = textwrap.fill(str(msg), width=text_width)

        for line in wrapped.splitlines():
            print(f'{line:<{text_width}}{label:>{label_width}}')

    def pmsg(self,msg,module=None,**kwargs):
        if not self.on:
            return

        text_width, label, label_width = self._get_text_width(module)

        buf = io.StringIO()
        pprint(msg,stream=buf, width=text_width,**kwargs)
        txt = buf.getvalue()
        for line in txt.splitlines():
            print(f'{line:<{text_width}}{label:>{label_width}}')

label instance-attribute

label = f'|(Debug message from {self.module_name})'

label_width instance-attribute

label_width = len(self.label)

module_name instance-attribute

module_name = frame.f_globals.get('__name__', '<unknown>')

on instance-attribute

on = False

__init__

__init__()
Source code in FoSpy/_debug.py
def __init__(self):
    self.on = False

    frame = inspect.currentframe().f_back
    self.module_name = frame.f_globals.get("__name__", "<unknown>")
    self.label = f"|(Debug message from {self.module_name})"
    self.label_width = len(self.label)

_get_text_width

_get_text_width(module=None)
Source code in FoSpy/_debug.py
def _get_text_width(self, module=None):
    if module:
        label = f"|(Debug message from {module} via {self.module_name})"
        label_width = len(label)
    else:
        label = self.label
        label_width = self.label_width

    text_width = DEBUG_WIDTH - label_width
    return text_width, label, label_width

msg

msg(msg, module=None)
Source code in FoSpy/_debug.py
def msg(self,msg, module=None):
    if not self.on:
        return

    text_width, label, label_width = self._get_text_width(module)

    wrapped = textwrap.fill(str(msg), width=text_width)

    for line in wrapped.splitlines():
        print(f'{line:<{text_width}}{label:>{label_width}}')

pmsg

pmsg(msg, module=None, **kwargs)
Source code in FoSpy/_debug.py
def pmsg(self,msg,module=None,**kwargs):
    if not self.on:
        return

    text_width, label, label_width = self._get_text_width(module)

    buf = io.StringIO()
    pprint(msg,stream=buf, width=text_width,**kwargs)
    txt = buf.getvalue()
    for line in txt.splitlines():
        print(f'{line:<{text_width}}{label:>{label_width}}')

build_block_header_regex

build_block_header_regex(spec)
Source code in FoSpy/parsing/regex.py
def build_block_header_regex(spec):
    single = spec["single"]
    list_ = spec["list"]

    pattern = (
        rf"^(?:"
        rf"{re.escape(list_['open'])}(?P<list_name>[^\]]+){re.escape(list_['close'])}"
        rf"|"
        rf"{re.escape(single['open'])}(?P<single_name>[^\]]+){re.escape(single['close'])}"
        rf")$"
    )
    return re.compile(pattern)

build_calc_comment_regex

build_calc_comment_regex(spec)
Matches calculated comments of the form

Example: // ## Calculated MW: 123.45 g/mol

Source code in FoSpy/parsing/regex.py
def build_calc_comment_regex(spec):
    """
    Matches calculated comments of the form:
        <comment_prefix> <calc_prefix> <text>
    Example:
        // ## Calculated MW: 123.45 g/mol
    """
    comment_prefix = re.escape(SYNTAX["comment"]["prefix"])
    calc_prefix = re.escape(spec["prefix"])

    # Allow leading whitespace before the comment prefix
    return re.compile(
        rf"^\s*{comment_prefix}\s+{calc_prefix}\s+(?P<text>.*)$"
    )

build_comment_regex

build_comment_regex(spec)
Source code in FoSpy/parsing/regex.py
def build_comment_regex(spec):
    prefix = re.escape(spec["prefix"])  # usually "//"
    allow_ws = spec.get("allow_leading_ws", True)

    if allow_ws:
        pattern = rf"^\s*{prefix}(?P<text>.*)$"
    else:
        pattern = rf"^{prefix}(?P<text>.*)$"

    return re.compile(pattern)

build_embedded_end_regex

build_embedded_end_regex(spec)
Source code in FoSpy/parsing/regex.py
def build_embedded_end_regex(spec):
    prefix = re.escape(spec["prefix"])
    close_tok = re.escape(spec["close"])

    pattern = rf"^{prefix}*\s*{close_tok}\s*$"
    return re.compile(pattern)

build_embedded_start_regex

build_embedded_start_regex(spec)
Source code in FoSpy/parsing/regex.py
def build_embedded_start_regex(spec):
    open_tok = re.escape(SYNTAX["embedded"]["open"])
    return re.compile(rf".*{open_tok}.*")

build_key_value_regex

build_key_value_regex(spec)
Source code in FoSpy/parsing/regex.py
def build_key_value_regex(spec):
    delim = re.escape(spec["delimiter"])
    prefix = spec.get("prefix")

    # Key cannot contain the delimiter
    if prefix:
        prefix_esc = re.escape(prefix)
        key_pattern = rf"{prefix_esc}(?P<key>[^{delim}]+)"
    else:
        key_pattern = rf"(?P<key>[^{delim}]+)"

    if spec["require_value"]:
        pattern = rf"^{key_pattern}\s*{delim}\s*(?P<val>.+)$"
    else:
        pattern = rf"^{key_pattern}\s*{delim}\s*(?P<val>.*)$"

    return re.compile(pattern)

build_loop_key_regex

build_loop_key_regex(spec)
Source code in FoSpy/parsing/regex.py
def build_loop_key_regex(spec):
    prefix = spec.get("prefix")
    delim  = re.escape(spec["delimiter"])

    if prefix:
        # Require key followed by prefix, e.g. "key_"
        prefix = re.escape(prefix)
        pattern = rf"^(?P<key>[^{prefix}]+){prefix}$"
    else:
        # Default: delimiter before key, e.g. ":key"
        pattern = rf"^{delim}(?P<key>[^{delim}]+)$"

    return re.compile(pattern)

build_nested_start_regex

build_nested_start_regex(spec)
Source code in FoSpy/parsing/regex.py
def build_nested_start_regex(spec):
    open_bracket = re.escape(spec["open"])  # usually "["

    pattern = (
        rf"^{open_bracket}"
        rf"(?P<list>{open_bracket})?"
        rf"(?P<rest>.*)$"
    )

    return re.compile(pattern)

refresh

refresh()
Source code in FoSpy/parsing/regex.py
def refresh():
    global BLOCK_HEADER, KEY_VALUE, COMMENT_LINE, CALC_COMMENT_LINE, NESTED_START, LOOP_KEY, EMBEDDED_START, EMBEDDED_END

    BLOCK_HEADER = build_block_header_regex(SYNTAX["block_header"])
    KEY_VALUE = build_key_value_regex(SYNTAX["key_value"])
    COMMENT_LINE = build_comment_regex(SYNTAX["comment"])
    CALC_COMMENT_LINE = build_calc_comment_regex(SYNTAX["calc_comment"])
    NESTED_START = build_nested_start_regex(SYNTAX["nested"])
    LOOP_KEY = build_loop_key_regex(SYNTAX["key_value"])
    COMMENT_LINE = build_comment_regex(SYNTAX["comment"])
    EMBEDDED_START = build_embedded_start_regex(SYNTAX["embedded"])
    EMBEDDED_END = build_embedded_end_regex(SYNTAX["embedded"])