Conditional writes DSL for Dynantic.
This module provides a DynCondition wrapper and Attr builder that create
condition expressions compatible with DynamoDB's ConditionExpression.
It delegates expression building to boto3's internal ConditionExpressionBuilder
while keeping boto3 internals hidden from the public API.
Design:
- DynCondition wraps boto3 ConditionBase, stored in .raw attribute
- Attr builder wraps boto3 Attr internally, returns DynCondition
- Operators &, |, ~ on DynCondition produce new DynCondition instances
- At compilation time, DynCondition.raw is fed to boto3's builder
Usage
from dynantic import Attr
Simple conditions
user.save(condition=Attr("email").not_exists())
user.save(condition=Attr("version") == 1)
Composed conditions
condition = (Attr("age") >= 18) & (Attr("status") == "active")
user.save(condition=condition)
Attr
Represents a DynamoDB attribute for building conditions.
This class wraps boto3.dynamodb.conditions.Attr internally and provides
a clean API for building condition expressions. All methods return
DynCondition instances (not raw boto3 objects).
Usage
Comparison operators
Attr("age") >= 18
Attr("status") == "active"
Attr("score") < 100
DynamoDB functions
Attr("email").not_exists() # For create-if-not-exists
Attr("name").begins_with("A")
Attr("tags").contains("premium")
Attr("age").between(18, 65)
Attr("status").is_in(["active", "pending"])
Source code in dynantic/conditions.py
| class Attr:
"""
Represents a DynamoDB attribute for building conditions.
This class wraps boto3.dynamodb.conditions.Attr internally and provides
a clean API for building condition expressions. All methods return
DynCondition instances (not raw boto3 objects).
Usage:
# Comparison operators
Attr("age") >= 18
Attr("status") == "active"
Attr("score") < 100
# DynamoDB functions
Attr("email").not_exists() # For create-if-not-exists
Attr("name").begins_with("A")
Attr("tags").contains("premium")
Attr("age").between(18, 65)
Attr("status").is_in(["active", "pending"])
"""
__slots__ = ("name", "_boto3_attr")
def __init__(self, name: str) -> None:
"""
Initialize an attribute reference.
Args:
name: The attribute name in DynamoDB
"""
self.name = name
self._boto3_attr = Boto3Attr(name)
# Comparison Operators - all return DynCondition
def __eq__(self, value: Any) -> DynCondition: # type: ignore[override]
"""Equals condition: Attr("field") == value"""
return DynCondition(self._boto3_attr.eq(value))
def __ne__(self, value: Any) -> DynCondition: # type: ignore[override]
"""Not equals condition: Attr("field") != value"""
return DynCondition(self._boto3_attr.ne(value))
def __lt__(self, value: Any) -> DynCondition:
"""Less than condition: Attr("field") < value"""
return DynCondition(self._boto3_attr.lt(value))
def __le__(self, value: Any) -> DynCondition:
"""Less than or equal condition: Attr("field") <= value"""
return DynCondition(self._boto3_attr.lte(value))
def __gt__(self, value: Any) -> DynCondition:
"""Greater than condition: Attr("field") > value"""
return DynCondition(self._boto3_attr.gt(value))
def __ge__(self, value: Any) -> DynCondition:
"""Greater than or equal condition: Attr("field") >= value"""
return DynCondition(self._boto3_attr.gte(value))
# DynamoDB Function Methods - all return DynCondition
def exists(self) -> DynCondition:
"""
Checks if the attribute exists.
Usage:
Attr("optional_field").exists()
"""
return DynCondition(self._boto3_attr.exists())
def not_exists(self) -> DynCondition:
"""
Checks if the attribute does NOT exist.
Common use case: Create-if-not-exists pattern
Usage:
user.save(condition=Attr("email").not_exists())
"""
return DynCondition(self._boto3_attr.not_exists())
def begins_with(self, prefix: str) -> DynCondition:
"""
Checks if string attribute begins with prefix.
Usage:
Attr("name").begins_with("John")
"""
return DynCondition(self._boto3_attr.begins_with(prefix))
def contains(self, value: Any) -> DynCondition:
"""
Checks if attribute contains value.
For strings: substring match
For lists/sets: membership check
Usage:
Attr("email").contains("@gmail.com")
Attr("tags").contains("premium")
"""
return DynCondition(self._boto3_attr.contains(value))
def between(self, low: Any, high: Any) -> DynCondition:
"""
Checks if attribute is between low and high (inclusive).
Usage:
Attr("age").between(18, 65)
"""
return DynCondition(self._boto3_attr.between(low, high))
def is_in(self, values: list[Any]) -> DynCondition:
"""
Checks if attribute value is in the provided list.
Usage:
Attr("status").is_in(["active", "pending", "review"])
"""
return DynCondition(self._boto3_attr.is_in(values))
def __repr__(self) -> str:
return f"Attr({self.name!r})"
|
__init__
__init__(name: str) -> None
Initialize an attribute reference.
Parameters:
| Name |
Type |
Description |
Default |
name
|
str
|
The attribute name in DynamoDB
|
required
|
Source code in dynantic/conditions.py
| def __init__(self, name: str) -> None:
"""
Initialize an attribute reference.
Args:
name: The attribute name in DynamoDB
"""
self.name = name
self._boto3_attr = Boto3Attr(name)
|
__eq__
__eq__(value: Any) -> DynCondition
Equals condition: Attr("field") == value
Source code in dynantic/conditions.py
| def __eq__(self, value: Any) -> DynCondition: # type: ignore[override]
"""Equals condition: Attr("field") == value"""
return DynCondition(self._boto3_attr.eq(value))
|
__ne__
__ne__(value: Any) -> DynCondition
Not equals condition: Attr("field") != value
Source code in dynantic/conditions.py
| def __ne__(self, value: Any) -> DynCondition: # type: ignore[override]
"""Not equals condition: Attr("field") != value"""
return DynCondition(self._boto3_attr.ne(value))
|
__lt__
__lt__(value: Any) -> DynCondition
Less than condition: Attr("field") < value
Source code in dynantic/conditions.py
| def __lt__(self, value: Any) -> DynCondition:
"""Less than condition: Attr("field") < value"""
return DynCondition(self._boto3_attr.lt(value))
|
__le__
__le__(value: Any) -> DynCondition
Less than or equal condition: Attr("field") <= value
Source code in dynantic/conditions.py
| def __le__(self, value: Any) -> DynCondition:
"""Less than or equal condition: Attr("field") <= value"""
return DynCondition(self._boto3_attr.lte(value))
|
__gt__
__gt__(value: Any) -> DynCondition
Greater than condition: Attr("field") > value
Source code in dynantic/conditions.py
| def __gt__(self, value: Any) -> DynCondition:
"""Greater than condition: Attr("field") > value"""
return DynCondition(self._boto3_attr.gt(value))
|
__ge__
__ge__(value: Any) -> DynCondition
Greater than or equal condition: Attr("field") >= value
Source code in dynantic/conditions.py
| def __ge__(self, value: Any) -> DynCondition:
"""Greater than or equal condition: Attr("field") >= value"""
return DynCondition(self._boto3_attr.gte(value))
|
exists
Checks if the attribute exists.
Usage
Attr("optional_field").exists()
Source code in dynantic/conditions.py
| def exists(self) -> DynCondition:
"""
Checks if the attribute exists.
Usage:
Attr("optional_field").exists()
"""
return DynCondition(self._boto3_attr.exists())
|
not_exists
not_exists() -> DynCondition
Checks if the attribute does NOT exist.
Common use case: Create-if-not-exists pattern
Usage
user.save(condition=Attr("email").not_exists())
Source code in dynantic/conditions.py
| def not_exists(self) -> DynCondition:
"""
Checks if the attribute does NOT exist.
Common use case: Create-if-not-exists pattern
Usage:
user.save(condition=Attr("email").not_exists())
"""
return DynCondition(self._boto3_attr.not_exists())
|
begins_with
begins_with(prefix: str) -> DynCondition
Checks if string attribute begins with prefix.
Usage
Attr("name").begins_with("John")
Source code in dynantic/conditions.py
| def begins_with(self, prefix: str) -> DynCondition:
"""
Checks if string attribute begins with prefix.
Usage:
Attr("name").begins_with("John")
"""
return DynCondition(self._boto3_attr.begins_with(prefix))
|
contains
contains(value: Any) -> DynCondition
Checks if attribute contains value.
For strings: substring match
For lists/sets: membership check
Usage
Attr("email").contains("@gmail.com")
Attr("tags").contains("premium")
Source code in dynantic/conditions.py
| def contains(self, value: Any) -> DynCondition:
"""
Checks if attribute contains value.
For strings: substring match
For lists/sets: membership check
Usage:
Attr("email").contains("@gmail.com")
Attr("tags").contains("premium")
"""
return DynCondition(self._boto3_attr.contains(value))
|
between
between(low: Any, high: Any) -> DynCondition
Checks if attribute is between low and high (inclusive).
Usage
Attr("age").between(18, 65)
Source code in dynantic/conditions.py
| def between(self, low: Any, high: Any) -> DynCondition:
"""
Checks if attribute is between low and high (inclusive).
Usage:
Attr("age").between(18, 65)
"""
return DynCondition(self._boto3_attr.between(low, high))
|
is_in
is_in(values: list[Any]) -> DynCondition
Checks if attribute value is in the provided list.
Usage
Attr("status").is_in(["active", "pending", "review"])
Source code in dynantic/conditions.py
| def is_in(self, values: list[Any]) -> DynCondition:
"""
Checks if attribute value is in the provided list.
Usage:
Attr("status").is_in(["active", "pending", "review"])
"""
return DynCondition(self._boto3_attr.is_in(values))
|
DynCondition
Dynantic-owned wrapper for DynamoDB condition expressions.
This class wraps a boto3 condition object (stored in .raw) and provides
Python operators for composing conditions. It keeps boto3 internals
hidden from the public API while delegating expression correctness
to boto3.
Users typically don't instantiate this directly - use Attr() instead.
Attributes:
| Name |
Type |
Description |
raw |
|
The underlying boto3 ConditionBase object (internal use)
|
Source code in dynantic/conditions.py
| class DynCondition:
"""
Dynantic-owned wrapper for DynamoDB condition expressions.
This class wraps a boto3 condition object (stored in .raw) and provides
Python operators for composing conditions. It keeps boto3 internals
hidden from the public API while delegating expression correctness
to boto3.
Users typically don't instantiate this directly - use Attr() instead.
Attributes:
raw: The underlying boto3 ConditionBase object (internal use)
"""
__slots__ = ("raw",)
def __init__(self, raw: Boto3ConditionBase) -> None:
"""
Initialize with a boto3 condition object.
Args:
raw: The underlying boto3 condition (internal)
"""
self.raw = raw
def __and__(self, other: Condition) -> DynCondition:
"""
Combine conditions with AND.
Usage:
condition = (Attr("age") >= 18) & (Attr("active") == True)
"""
other_raw = _extract_raw(other)
return DynCondition(Boto3And(self.raw, other_raw))
def __rand__(self, other: Condition) -> DynCondition:
"""Support for: boto3_condition & DynCondition"""
other_raw = _extract_raw(other)
return DynCondition(Boto3And(other_raw, self.raw))
def __or__(self, other: Condition) -> DynCondition:
"""
Combine conditions with OR.
Usage:
condition = (Attr("role") == "admin") | (Attr("role") == "moderator")
"""
other_raw = _extract_raw(other)
return DynCondition(Boto3Or(self.raw, other_raw))
def __ror__(self, other: Condition) -> DynCondition:
"""Support for: boto3_condition | DynCondition"""
other_raw = _extract_raw(other)
return DynCondition(Boto3Or(other_raw, self.raw))
def __invert__(self) -> DynCondition:
"""
Negate a condition with NOT.
Usage:
condition = ~Attr("deleted").exists()
"""
return DynCondition(Boto3Not(self.raw))
def __repr__(self) -> str:
return f"DynCondition({self.raw!r})"
|
__init__
__init__(raw: ConditionBase) -> None
Initialize with a boto3 condition object.
Parameters:
| Name |
Type |
Description |
Default |
raw
|
ConditionBase
|
The underlying boto3 condition (internal)
|
required
|
Source code in dynantic/conditions.py
| def __init__(self, raw: Boto3ConditionBase) -> None:
"""
Initialize with a boto3 condition object.
Args:
raw: The underlying boto3 condition (internal)
"""
self.raw = raw
|
__and__
__and__(other: Condition) -> DynCondition
Combine conditions with AND.
Usage
condition = (Attr("age") >= 18) & (Attr("active") == True)
Source code in dynantic/conditions.py
| def __and__(self, other: Condition) -> DynCondition:
"""
Combine conditions with AND.
Usage:
condition = (Attr("age") >= 18) & (Attr("active") == True)
"""
other_raw = _extract_raw(other)
return DynCondition(Boto3And(self.raw, other_raw))
|
__rand__
__rand__(other: Condition) -> DynCondition
Support for: boto3_condition & DynCondition
Source code in dynantic/conditions.py
| def __rand__(self, other: Condition) -> DynCondition:
"""Support for: boto3_condition & DynCondition"""
other_raw = _extract_raw(other)
return DynCondition(Boto3And(other_raw, self.raw))
|
__or__
__or__(other: Condition) -> DynCondition
Combine conditions with OR.
Usage
condition = (Attr("role") == "admin") | (Attr("role") == "moderator")
Source code in dynantic/conditions.py
| def __or__(self, other: Condition) -> DynCondition:
"""
Combine conditions with OR.
Usage:
condition = (Attr("role") == "admin") | (Attr("role") == "moderator")
"""
other_raw = _extract_raw(other)
return DynCondition(Boto3Or(self.raw, other_raw))
|
__ror__
__ror__(other: Condition) -> DynCondition
Support for: boto3_condition | DynCondition
Source code in dynantic/conditions.py
| def __ror__(self, other: Condition) -> DynCondition:
"""Support for: boto3_condition | DynCondition"""
other_raw = _extract_raw(other)
return DynCondition(Boto3Or(other_raw, self.raw))
|
__invert__
__invert__() -> DynCondition
Negate a condition with NOT.
Usage
condition = ~Attr("deleted").exists()
Source code in dynantic/conditions.py
| def __invert__(self) -> DynCondition:
"""
Negate a condition with NOT.
Usage:
condition = ~Attr("deleted").exists()
"""
return DynCondition(Boto3Not(self.raw))
|