Skip to content

synt.expr.comprehension ¤

Comprehension ¤

Bases: IntoExpression, IntoCode

A Comprehension expression.

Attribute explanation:

[
    a           # elt, aka "extract, load, transform"
                # 👇 generator node #1
    for b       # target
    in c        # iter
    if          # `if`s
        d == e  # an `if`

    for f in g  # 👈 generator node #2
]

Note: Comprehension is not a subclass of expr.Expression. However, it implements expr.IntoExpression, and will be internally converted into GeneratorComprehension.

References

comprehension.

Source code in synt/expr/comprehension.py
class Comprehension(expr.IntoExpression, code.IntoCode):
    r"""A Comprehension expression.

    **Attribute explanation:**
    ```python
    [
        a           # elt, aka "extract, load, transform"
                    # 👇 generator node #1
        for b       # target
        in c        # iter
        if          # `if`s
            d == e  # an `if`

        for f in g  # 👈 generator node #2
    ]
    ```

    **Note:**
    `Comprehension` is not a subclass of [`expr.Expression`][synt.expr.expr.Expression].
    However, it implements [`expr.IntoExpression`][synt.expr.expr.IntoExpression],
    and will be internally converted into [`GeneratorComprehension`][synt.expr.comprehension.GeneratorComprehension].

    References:
        [`comprehension`](https://docs.python.org/3/reference/
        expressions.html#grammar-tokens-python-grammar-comprehension).
    """

    elt: expr.Expression
    """The expression to evaluate when iterating over the
    [`iterator`][synt.expr.comprehension.ComprehensionNode.iterator].

    **Note:** aka "extract, load, transform"."""
    comprehensions: list[ComprehensionNode]
    """Generator nodes."""

    precedence = expr.ExprPrecedence.Atom

    def __init__(
        self,
        elt: expr.IntoExpression,
        comprehensions: list[ComprehensionNode],
    ):
        """Initialize a new comprehension expression.

        Args:
            elt: The expression to evaluate.
            comprehensions: The generator nodes.
        """
        self.elt = elt.into_expression()
        self.comprehensions = comprehensions

    def into_expression(self) -> GeneratorComprehension:
        return GeneratorComprehension(self)

    def into_code(self) -> str:
        comp_text = " ".join(x.into_code() for x in self.comprehensions)
        return f"{self.elt.into_code()} {comp_text}"

precedence class-attribute instance-attribute ¤

precedence = Atom

elt instance-attribute ¤

elt: Expression = into_expression()

The expression to evaluate when iterating over the iterator.

Note: aka "extract, load, transform".

comprehensions instance-attribute ¤

Generator nodes.

__init__ ¤

1
2
3
4
__init__(
    elt: IntoExpression,
    comprehensions: list[ComprehensionNode],
)

Initialize a new comprehension expression.

Parameters:

Name Type Description Default
elt IntoExpression

The expression to evaluate.

required
comprehensions list[ComprehensionNode]

The generator nodes.

required
Source code in synt/expr/comprehension.py
def __init__(
    self,
    elt: expr.IntoExpression,
    comprehensions: list[ComprehensionNode],
):
    """Initialize a new comprehension expression.

    Args:
        elt: The expression to evaluate.
        comprehensions: The generator nodes.
    """
    self.elt = elt.into_expression()
    self.comprehensions = comprehensions

into_expression ¤

into_expression() -> GeneratorComprehension
Source code in synt/expr/comprehension.py
def into_expression(self) -> GeneratorComprehension:
    return GeneratorComprehension(self)

into_code ¤

into_code() -> str
Source code in synt/expr/comprehension.py
def into_code(self) -> str:
    comp_text = " ".join(x.into_code() for x in self.comprehensions)
    return f"{self.elt.into_code()} {comp_text}"

ComprehensionNode ¤

Bases: IntoCode

Source code in synt/expr/comprehension.py
class ComprehensionNode(code.IntoCode):
    target: list[Identifier]
    """Comprehension `for`-loop target identifiers."""
    iterator: expr.Expression
    """The iterator to iterate over."""
    ifs: list[expr.Expression]
    """A list of `if` expressions to filter comprehension result."""
    is_async: bool
    """Whether the iterator is asynchronous."""

    precedence = expr.ExprPrecedence.Atom

    def __init__(
        self,
        target: list[Identifier],
        iterator: expr.IntoExpression,
        ifs: list[expr.IntoExpression],
        is_async: bool,
    ):
        """Initialize a new comprehension expression.

        Args:
            target: The target identifiers.
            iterator: The iterator to iterate over.
            ifs: A list of `if` expressions.
            is_async: Whether the iterator is asynchronous.
        """
        self.target = target
        self.iterator = iterator.into_expression()
        self.ifs = [x.into_expression() for x in ifs]
        self.is_async = is_async

    def into_code(self) -> str:
        target_text = ", ".join(t.into_code() for t in self.target)
        if self.ifs:
            if_text = " " + " ".join(f"if {i.into_code()}" for i in self.ifs)
        else:
            if_text = ""
        for_text = "async for" if self.is_async else "for"
        return f"{for_text} {target_text} in {self.iterator.into_code()}{if_text}"

precedence class-attribute instance-attribute ¤

precedence = Atom

target instance-attribute ¤

target: list[Identifier] = target

Comprehension for-loop target identifiers.

iterator instance-attribute ¤

iterator: Expression = into_expression()

The iterator to iterate over.

ifs instance-attribute ¤

ifs: list[Expression] = [into_expression() for x in ifs]

A list of if expressions to filter comprehension result.

is_async instance-attribute ¤

is_async: bool = is_async

Whether the iterator is asynchronous.

__init__ ¤

1
2
3
4
5
6
__init__(
    target: list[Identifier],
    iterator: IntoExpression,
    ifs: list[IntoExpression],
    is_async: bool,
)

Initialize a new comprehension expression.

Parameters:

Name Type Description Default
target list[Identifier]

The target identifiers.

required
iterator IntoExpression

The iterator to iterate over.

required
ifs list[IntoExpression]

A list of if expressions.

required
is_async bool

Whether the iterator is asynchronous.

required
Source code in synt/expr/comprehension.py
def __init__(
    self,
    target: list[Identifier],
    iterator: expr.IntoExpression,
    ifs: list[expr.IntoExpression],
    is_async: bool,
):
    """Initialize a new comprehension expression.

    Args:
        target: The target identifiers.
        iterator: The iterator to iterate over.
        ifs: A list of `if` expressions.
        is_async: Whether the iterator is asynchronous.
    """
    self.target = target
    self.iterator = iterator.into_expression()
    self.ifs = [x.into_expression() for x in ifs]
    self.is_async = is_async

into_code ¤

into_code() -> str
Source code in synt/expr/comprehension.py
def into_code(self) -> str:
    target_text = ", ".join(t.into_code() for t in self.target)
    if self.ifs:
        if_text = " " + " ".join(f"if {i.into_code()}" for i in self.ifs)
    else:
        if_text = ""
    for_text = "async for" if self.is_async else "for"
    return f"{for_text} {target_text} in {self.iterator.into_code()}{if_text}"

GeneratorComprehension ¤

Bases: Expression

A generator comprehension expression.

Note: GeneratorComprehension is a subclass of expr.Expression, working as a wrapper for Comprehension.

Source code in synt/expr/comprehension.py
class GeneratorComprehension(expr.Expression):
    r"""A generator comprehension expression.

    **Note:**
    `GeneratorComprehension` is a subclass of [`expr.Expression`][synt.expr.expr.Expression],
    working as a wrapper for [`Comprehension`][synt.expr.comprehension.Comprehension].
    """

    comprehension: Comprehension
    """The inner comprehension expression."""

    precedence = expr.ExprPrecedence.Atom
    expr_type = expr.ExprType.Comprehension

    def __init__(self, comprehension: Comprehension):
        """Initialize a generator comprehension expression.

        Args:
            comprehension: The inner comprehension expression to wrap.
        """
        self.comprehension = comprehension

    def into_code(self) -> str:
        return f"({self.comprehension.into_code()})"

precedence class-attribute instance-attribute ¤

precedence = Atom

expr_type class-attribute instance-attribute ¤

expr_type = Comprehension

comprehension instance-attribute ¤

comprehension: Comprehension = comprehension

The inner comprehension expression.

__init__ ¤

__init__(comprehension: Comprehension)

Initialize a generator comprehension expression.

Parameters:

Name Type Description Default
comprehension Comprehension

The inner comprehension expression to wrap.

required
Source code in synt/expr/comprehension.py
def __init__(self, comprehension: Comprehension):
    """Initialize a generator comprehension expression.

    Args:
        comprehension: The inner comprehension expression to wrap.
    """
    self.comprehension = comprehension

into_code ¤

into_code() -> str
Source code in synt/expr/comprehension.py
def into_code(self) -> str:
    return f"({self.comprehension.into_code()})"

ComprehensionBuilder ¤

Bases: IntoExpression

Builder for Comprehension.

Source code in synt/expr/comprehension.py
class ComprehensionBuilder(expr.IntoExpression):
    r"""Builder for [`Comprehension`][synt.expr.comprehension.Comprehension]."""

    __elt: expr.Expression
    __comprehensions: list[ComprehensionNode]
    __curr_node: ComprehensionNodeBuilder | None

    def __init__(
        self,
        elt: expr.IntoExpression,
        target: list[ident.Identifier],
        is_async: bool = False,
    ):
        """Initialize a generator comprehension expression.

        Args:
            elt: The expression to evaluate.
            target: The target of the iteration.
            is_async: Whether the comprehension is asynchronous.
        """
        self.__elt = elt.into_expression()
        self.__comprehensions = []
        self.__curr_node = ComprehensionNodeBuilder(self, is_async).target(*target)

    @staticmethod
    def init(
        elt: expr.IntoExpression, target: list[ident.Identifier], is_async: bool = False
    ) -> ComprehensionNodeBuilder:
        """Initialize a generator comprehension expression and return the first node builder.

        Args:
            elt: The expression to evaluate.
            target: The target of the iteration.
            is_async: Whether the comprehension is asynchronous.
        """
        return ComprehensionBuilder(elt, target, is_async).curr_node()  # type:ignore[return-value]

    def curr_node(self) -> ComprehensionNodeBuilder | None:
        """Returns the current node builder."""
        return self.__curr_node

    def __finish_node_builder(self) -> None:
        if self.__curr_node:
            res = self.__curr_node.build()
            self.__comprehensions.append(res)
            self.__curr_node = None

    def for_(self, iterator: expr.IntoExpression) -> ComprehensionNodeBuilder:
        """Create a new comprehension node.

        This will finish the previous [`ComprehensionNodeBuilder`][synt.expr.comprehension.ComprehensionNodeBuilder]
        and start a new one.
        """
        self.__finish_node_builder()
        return ComprehensionNodeBuilder(self).iterator(iterator)

    def async_for(self, iterator: expr.IntoExpression) -> ComprehensionNodeBuilder:
        """Create a new async comprehension node.

        This will finish the previous [`ComprehensionNodeBuilder`][synt.expr.comprehension.ComprehensionNodeBuilder]
        and start a new one.
        """
        self.__finish_node_builder()
        return ComprehensionNodeBuilder(self, True).iterator(iterator)

    def build(self) -> Comprehension:
        """Build the comprehension expression.

        Raises:
            ValueError: If any required fields are missing.
        """
        self.__finish_node_builder()
        return Comprehension(self.__elt, self.__comprehensions)

    def into_expression(self) -> GeneratorComprehension:
        return self.build().into_expression()

__init__ ¤

1
2
3
4
5
__init__(
    elt: IntoExpression,
    target: list[Identifier],
    is_async: bool = False,
)

Initialize a generator comprehension expression.

Parameters:

Name Type Description Default
elt IntoExpression

The expression to evaluate.

required
target list[Identifier]

The target of the iteration.

required
is_async bool

Whether the comprehension is asynchronous.

False
Source code in synt/expr/comprehension.py
def __init__(
    self,
    elt: expr.IntoExpression,
    target: list[ident.Identifier],
    is_async: bool = False,
):
    """Initialize a generator comprehension expression.

    Args:
        elt: The expression to evaluate.
        target: The target of the iteration.
        is_async: Whether the comprehension is asynchronous.
    """
    self.__elt = elt.into_expression()
    self.__comprehensions = []
    self.__curr_node = ComprehensionNodeBuilder(self, is_async).target(*target)

init staticmethod ¤

1
2
3
4
5
init(
    elt: IntoExpression,
    target: list[Identifier],
    is_async: bool = False,
) -> ComprehensionNodeBuilder

Initialize a generator comprehension expression and return the first node builder.

Parameters:

Name Type Description Default
elt IntoExpression

The expression to evaluate.

required
target list[Identifier]

The target of the iteration.

required
is_async bool

Whether the comprehension is asynchronous.

False
Source code in synt/expr/comprehension.py
@staticmethod
def init(
    elt: expr.IntoExpression, target: list[ident.Identifier], is_async: bool = False
) -> ComprehensionNodeBuilder:
    """Initialize a generator comprehension expression and return the first node builder.

    Args:
        elt: The expression to evaluate.
        target: The target of the iteration.
        is_async: Whether the comprehension is asynchronous.
    """
    return ComprehensionBuilder(elt, target, is_async).curr_node()  # type:ignore[return-value]

curr_node ¤

curr_node() -> ComprehensionNodeBuilder | None

Returns the current node builder.

Source code in synt/expr/comprehension.py
def curr_node(self) -> ComprehensionNodeBuilder | None:
    """Returns the current node builder."""
    return self.__curr_node

for_ ¤

Create a new comprehension node.

This will finish the previous ComprehensionNodeBuilder and start a new one.

Source code in synt/expr/comprehension.py
def for_(self, iterator: expr.IntoExpression) -> ComprehensionNodeBuilder:
    """Create a new comprehension node.

    This will finish the previous [`ComprehensionNodeBuilder`][synt.expr.comprehension.ComprehensionNodeBuilder]
    and start a new one.
    """
    self.__finish_node_builder()
    return ComprehensionNodeBuilder(self).iterator(iterator)

async_for ¤

1
2
3
async_for(
    iterator: IntoExpression,
) -> ComprehensionNodeBuilder

Create a new async comprehension node.

This will finish the previous ComprehensionNodeBuilder and start a new one.

Source code in synt/expr/comprehension.py
def async_for(self, iterator: expr.IntoExpression) -> ComprehensionNodeBuilder:
    """Create a new async comprehension node.

    This will finish the previous [`ComprehensionNodeBuilder`][synt.expr.comprehension.ComprehensionNodeBuilder]
    and start a new one.
    """
    self.__finish_node_builder()
    return ComprehensionNodeBuilder(self, True).iterator(iterator)

build ¤

build() -> Comprehension

Build the comprehension expression.

Raises:

Type Description
ValueError

If any required fields are missing.

Source code in synt/expr/comprehension.py
def build(self) -> Comprehension:
    """Build the comprehension expression.

    Raises:
        ValueError: If any required fields are missing.
    """
    self.__finish_node_builder()
    return Comprehension(self.__elt, self.__comprehensions)

into_expression ¤

into_expression() -> GeneratorComprehension
Source code in synt/expr/comprehension.py
def into_expression(self) -> GeneratorComprehension:
    return self.build().into_expression()

ComprehensionNodeBuilder ¤

Bases: IntoExpression

Builder for ComprehensionNode.

Source code in synt/expr/comprehension.py
class ComprehensionNodeBuilder(expr.IntoExpression):
    r"""Builder for [`ComprehensionNode`][synt.expr.comprehension.ComprehensionNode]."""

    __target: list[Identifier] | None
    __iterator: expr.Expression | None
    __ifs: list[expr.IntoExpression]
    __is_async: bool = False

    def __init__(self, root: ComprehensionBuilder, is_async: bool = False):
        """Initialize an empty builder.

        Args:
            root: The root builder.
            is_async: Whether the comprehension is asynchronous.
        """
        self.root = root
        self.__is_async = is_async
        self.__target = None
        self.__iterator = None
        self.__ifs = []

    def target(self, *target: Identifier) -> Self:
        """Set the target of the comprehension generator.

        Args:
            target: The target identifiers.
        """
        self.__target = list(target)
        return self

    def in_(self, iterator: expr.IntoExpression) -> Self:
        """Alias [`iterator`][synt.expr.comprehension.ComprehensionNodeBuilder.iterator]."""
        return self.iterator(iterator)

    def iterator(self, iterator: expr.IntoExpression) -> Self:
        """Set the iterator of the comprehension generator.

        Args:
            iterator: The iterator to iterate over.
        """
        self.__iterator = iterator.into_expression()
        return self

    def if_(self, if_expr: expr.IntoExpression) -> Self:
        """Add an `if` expression to filter comprehension result.

        Args:
            if_expr: The `if` expression.
        """
        self.__ifs.append(if_expr.into_expression())
        return self

    def async_(self) -> Self:
        """Set the comprehension as asynchronous."""
        self.__is_async = True
        return self

    def sync(self) -> Self:
        """Set the comprehension as synchronous."""
        self.__is_async = False
        return self

    def build(self) -> ComprehensionNode:
        """Build the comprehension node.

        Raises:
            ValueError: If any required fields are missing.
        """
        err_fields = []
        if self.__iterator is None:
            err_fields.append("iterator")
        if not self.__target:
            err_fields.append("target")

        if err_fields:
            raise ValueError(
                f"Missing required fields: {', '.join(f'`{t}`' for t in err_fields)}"
            )
        return ComprehensionNode(
            self.__target,  # type:ignore[arg-type]
            self.__iterator,  # type:ignore[arg-type]
            self.__ifs,
            self.__is_async,
        )

    def for_(self, iterator: expr.IntoExpression) -> ComprehensionNodeBuilder:
        """Create a new comprehension node.

        This will call root's [`for_`][synt.expr.comprehension.ComprehensionBuilder.for_].
        """
        return self.root.for_(iterator)

    def async_for(self, iterator: expr.IntoExpression) -> ComprehensionNodeBuilder:
        """Create a new async comprehension node.

        This will call root's [`async_for`][synt.expr.comprehension.ComprehensionBuilder.async_for].
        """
        return self.root.async_for(iterator)

    def build_comp(self) -> Comprehension:
        """Build the comprehension expression.

        Raises:
            ValueError: If any required fields are missing.
        """
        return self.root.build()

    def into_expression(self) -> GeneratorComprehension:
        return self.build_comp().into_expression()

root instance-attribute ¤

root = root

__init__ ¤

1
2
3
__init__(
    root: ComprehensionBuilder, is_async: bool = False
)

Initialize an empty builder.

Parameters:

Name Type Description Default
root ComprehensionBuilder

The root builder.

required
is_async bool

Whether the comprehension is asynchronous.

False
Source code in synt/expr/comprehension.py
def __init__(self, root: ComprehensionBuilder, is_async: bool = False):
    """Initialize an empty builder.

    Args:
        root: The root builder.
        is_async: Whether the comprehension is asynchronous.
    """
    self.root = root
    self.__is_async = is_async
    self.__target = None
    self.__iterator = None
    self.__ifs = []

target ¤

target(*target: Identifier) -> Self

Set the target of the comprehension generator.

Parameters:

Name Type Description Default
target Identifier

The target identifiers.

()
Source code in synt/expr/comprehension.py
def target(self, *target: Identifier) -> Self:
    """Set the target of the comprehension generator.

    Args:
        target: The target identifiers.
    """
    self.__target = list(target)
    return self

in_ ¤

in_(iterator: IntoExpression) -> Self

Alias iterator.

Source code in synt/expr/comprehension.py
def in_(self, iterator: expr.IntoExpression) -> Self:
    """Alias [`iterator`][synt.expr.comprehension.ComprehensionNodeBuilder.iterator]."""
    return self.iterator(iterator)

iterator ¤

iterator(iterator: IntoExpression) -> Self

Set the iterator of the comprehension generator.

Parameters:

Name Type Description Default
iterator IntoExpression

The iterator to iterate over.

required
Source code in synt/expr/comprehension.py
def iterator(self, iterator: expr.IntoExpression) -> Self:
    """Set the iterator of the comprehension generator.

    Args:
        iterator: The iterator to iterate over.
    """
    self.__iterator = iterator.into_expression()
    return self

if_ ¤

if_(if_expr: IntoExpression) -> Self

Add an if expression to filter comprehension result.

Parameters:

Name Type Description Default
if_expr IntoExpression

The if expression.

required
Source code in synt/expr/comprehension.py
def if_(self, if_expr: expr.IntoExpression) -> Self:
    """Add an `if` expression to filter comprehension result.

    Args:
        if_expr: The `if` expression.
    """
    self.__ifs.append(if_expr.into_expression())
    return self

async_ ¤

async_() -> Self

Set the comprehension as asynchronous.

Source code in synt/expr/comprehension.py
def async_(self) -> Self:
    """Set the comprehension as asynchronous."""
    self.__is_async = True
    return self

sync ¤

sync() -> Self

Set the comprehension as synchronous.

Source code in synt/expr/comprehension.py
def sync(self) -> Self:
    """Set the comprehension as synchronous."""
    self.__is_async = False
    return self

build ¤

build() -> ComprehensionNode

Build the comprehension node.

Raises:

Type Description
ValueError

If any required fields are missing.

Source code in synt/expr/comprehension.py
def build(self) -> ComprehensionNode:
    """Build the comprehension node.

    Raises:
        ValueError: If any required fields are missing.
    """
    err_fields = []
    if self.__iterator is None:
        err_fields.append("iterator")
    if not self.__target:
        err_fields.append("target")

    if err_fields:
        raise ValueError(
            f"Missing required fields: {', '.join(f'`{t}`' for t in err_fields)}"
        )
    return ComprehensionNode(
        self.__target,  # type:ignore[arg-type]
        self.__iterator,  # type:ignore[arg-type]
        self.__ifs,
        self.__is_async,
    )

for_ ¤

Create a new comprehension node.

This will call root's for_.

Source code in synt/expr/comprehension.py
def for_(self, iterator: expr.IntoExpression) -> ComprehensionNodeBuilder:
    """Create a new comprehension node.

    This will call root's [`for_`][synt.expr.comprehension.ComprehensionBuilder.for_].
    """
    return self.root.for_(iterator)

async_for ¤

1
2
3
async_for(
    iterator: IntoExpression,
) -> ComprehensionNodeBuilder

Create a new async comprehension node.

This will call root's async_for.

Source code in synt/expr/comprehension.py
def async_for(self, iterator: expr.IntoExpression) -> ComprehensionNodeBuilder:
    """Create a new async comprehension node.

    This will call root's [`async_for`][synt.expr.comprehension.ComprehensionBuilder.async_for].
    """
    return self.root.async_for(iterator)

build_comp ¤

build_comp() -> Comprehension

Build the comprehension expression.

Raises:

Type Description
ValueError

If any required fields are missing.

Source code in synt/expr/comprehension.py
def build_comp(self) -> Comprehension:
    """Build the comprehension expression.

    Raises:
        ValueError: If any required fields are missing.
    """
    return self.root.build()

into_expression ¤

into_expression() -> GeneratorComprehension
Source code in synt/expr/comprehension.py
def into_expression(self) -> GeneratorComprehension:
    return self.build_comp().into_expression()