examples.27_email_value

Demonstrates trimming, lowercasing, and validating a simple email address using a ConstrainedValue pipeline.

This example shows:
  • How to normalize email addresses by trimming and lowercasing.
  • How to validate them against a simple regex pattern.
  • How to override __bool__ to indicate email validity directly.

⚠️ Note: This regex is intentionally minimal and not fully RFC 5322–compliant. It is only for basic demonstration of pipeline validation.

Run directly:

python examples/27_email_value.py

Expected output:

e1: True alice@example.com e2: False bad@@example

 1"""Demonstrates trimming, lowercasing, and validating a simple email address
 2using a :class:`ConstrainedValue` pipeline.
 3
 4This example shows:
 5  * How to normalize email addresses by trimming and lowercasing.
 6  * How to validate them against a simple regex pattern.
 7  * How to override `__bool__` to indicate email validity directly.
 8
 9> ⚠️ Note: This regex is intentionally minimal and not fully RFC 5322–compliant.
10  It is only for basic demonstration of pipeline validation.
11
12Run directly:
13
14    python examples/27_email_value.py
15
16Expected output:
17
18    e1: True alice@example.com
19    e2: False bad@@example
20"""
21
22import sys
23import pathlib
24import re
25from typing import List
26
27# ---------------------------------------------------------------------------
28# Make repo root importable when running this file directly
29# ---------------------------------------------------------------------------
30sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1]))
31
32from constrained_values import Response, Status, TypeValidationStrategy
33from constrained_values.value import TransformationStrategy, ConstrainedValue, PipeLineStrategy
34
35# Simple demonstration regex (non-exhaustive, but good for basic structure)
36EMAIL_RE = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")
37
38
39class TrimLower(TransformationStrategy[str, str]):
40    """Normalize an email string by trimming spaces and converting to lowercase."""
41
42    def transform(self, value: str) -> Response[str]:
43        """Trim whitespace and lowercase the input string.
44
45        Args:
46            value: The input email string.
47
48        Returns:
49            Response[str]: Contains:
50                * `status = Status.OK`
51                * `details = "normalize"`
52                * `value` — the normalized string
53        """
54        return Response(Status.OK, "normalize", value.strip().lower())
55
56
57class Email(ConstrainedValue[str]):
58    """A constrained value representing a normalized email address."""
59
60    def get_strategies(self) -> List[PipeLineStrategy]:
61        """Return the email normalization pipeline."""
62        return [TypeValidationStrategy(str), TrimLower()]
63
64    def __bool__(self) -> bool:
65        """Return `True` if the email passes normalization and regex validation."""
66        return self.ok and bool(EMAIL_RE.match(self.value))
67
68
69def main() -> None:
70    """Run the email normalization and validation demonstration.
71
72    Steps:
73        1. Create an `Email` with extra spaces and uppercase letters.
74        2. Create an invalid email with multiple `@` symbols.
75        3. Print the boolean validity and normalized value for each.
76
77    Prints:
78        * `"e1: True alice@example.com"`
79        * `"e2: False bad@@example"`
80    """
81    e1 = Email("  Alice@Example.com ")
82    print("e1:", bool(e1), e1.value)
83    e2 = Email("bad@@example")
84    print("e2:", bool(e2), e2.value)
85
86
87if __name__ == "__main__":
88    main()
EMAIL_RE = re.compile('^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$')
class TrimLower(constrained_values.value.TransformationStrategy[str, str]):
40class TrimLower(TransformationStrategy[str, str]):
41    """Normalize an email string by trimming spaces and converting to lowercase."""
42
43    def transform(self, value: str) -> Response[str]:
44        """Trim whitespace and lowercase the input string.
45
46        Args:
47            value: The input email string.
48
49        Returns:
50            Response[str]: Contains:
51                * `status = Status.OK`
52                * `details = "normalize"`
53                * `value` — the normalized string
54        """
55        return Response(Status.OK, "normalize", value.strip().lower())

Normalize an email string by trimming spaces and converting to lowercase.

def transform(self, value: str) -> constrained_values.Response[str]:
43    def transform(self, value: str) -> Response[str]:
44        """Trim whitespace and lowercase the input string.
45
46        Args:
47            value: The input email string.
48
49        Returns:
50            Response[str]: Contains:
51                * `status = Status.OK`
52                * `details = "normalize"`
53                * `value` — the normalized string
54        """
55        return Response(Status.OK, "normalize", value.strip().lower())

Trim whitespace and lowercase the input string.

Arguments:
  • value: The input email string.
Returns:

Response[str]: Contains: * status = Status.OK * details = "normalize" * value — the normalized string

class Email(constrained_values.value.ConstrainedValue[str]):
58class Email(ConstrainedValue[str]):
59    """A constrained value representing a normalized email address."""
60
61    def get_strategies(self) -> List[PipeLineStrategy]:
62        """Return the email normalization pipeline."""
63        return [TypeValidationStrategy(str), TrimLower()]
64
65    def __bool__(self) -> bool:
66        """Return `True` if the email passes normalization and regex validation."""
67        return self.ok and bool(EMAIL_RE.match(self.value))

A constrained value representing a normalized email address.

def get_strategies(self) -> List[constrained_values.value.PipeLineStrategy]:
61    def get_strategies(self) -> List[PipeLineStrategy]:
62        """Return the email normalization pipeline."""
63        return [TypeValidationStrategy(str), TrimLower()]

Return the email normalization pipeline.

Inherited Members
constrained_values.value.ConstrainedValue
ConstrainedValue
status
details
value
unwrap
ok
def main() -> None:
70def main() -> None:
71    """Run the email normalization and validation demonstration.
72
73    Steps:
74        1. Create an `Email` with extra spaces and uppercase letters.
75        2. Create an invalid email with multiple `@` symbols.
76        3. Print the boolean validity and normalized value for each.
77
78    Prints:
79        * `"e1: True alice@example.com"`
80        * `"e2: False bad@@example"`
81    """
82    e1 = Email("  Alice@Example.com ")
83    print("e1:", bool(e1), e1.value)
84    e2 = Email("bad@@example")
85    print("e2:", bool(e2), e2.value)

Run the email normalization and validation demonstration.

Steps:
  1. Create an Email with extra spaces and uppercase letters.
  2. Create an invalid email with multiple @ symbols.
  3. Print the boolean validity and normalized value for each.
Prints:
  • "e1: True alice@example.com"
  • "e2: False bad@@example"