valid8r.core.parsers
String parsing functions with Maybe monad error handling.
Classes
Structured URL components. |
|
Structured email address. |
|
Structured North American phone number (NANP). |
Functions
|
Parse and validate input is a string type. |
|
Parse a string to an integer. |
|
Parse a string to a floating-point number. |
|
Parse a string to a boolean value. |
|
Parse a string to a date object. |
|
Parse a string to a timezone-aware datetime object. |
|
Parse a string to a timedelta object. |
|
Parse a string to a complex number. |
|
Parse a string to a Decimal for precise decimal arithmetic. |
|
Parse a string to an enum member. |
|
Parse a string to a list using the specified element parser and separator. |
|
Parse a string to a dictionary using the specified parsers and separators. |
|
Parse a string to a set using the specified element parser and separator. |
|
Parse a string to an integer with range validation. |
|
Parse a string to a list with length validation. |
|
Parse a string to a dictionary with required keys validation. |
|
Create a parser function from a conversion function. |
|
Create a parser function from a conversion function with a decorator. |
|
Create a parser with a built-in validator. |
|
Parse a string to a UUID. |
|
Parse an IPv4 address string. |
|
Parse an IPv6 address string. |
|
Parse a string as either an IPv4 or IPv6 address. |
|
Parse a CIDR network string (IPv4 or IPv6). |
|
Parse a URL with light validation. |
|
Parse a bare email address of the form |
|
Parse a North American phone number (NANP format). |
|
Parse a URL-safe slug (lowercase letters, numbers, hyphens only). |
|
Parse a JSON string into a Python object. |
|
Parse and decode a base64-encoded string. |
|
Parse and validate a JWT (JSON Web Token) structure. |
|
Parse a string into a pathlib.Path object. |
Module Contents
- valid8r.core.parsers.parse_str(input_value, error_message=None, *, strip=True, allow_empty=True)[source]
Parse and validate input is a string type.
Validates that the input is actually a string type (isinstance check). By default, strips leading and trailing whitespace for consistency with other parsers like parse_int and parse_float.
This function provides type validation at the parser layer, ensuring the input is a string before any content validation is applied. It complements the validator layer which handles content rules like non-empty, length constraints, or pattern matching.
- Parameters:
input_value (object) – Value to validate (any type accepted, only str passes).
error_message (str | None) – Optional custom error message for type validation failures. If not provided, generates descriptive error based on actual type received.
strip (bool) – If True (default), strip leading and trailing whitespace from the input. This provides consistency with other parsers like parse_int. Set to False to preserve whitespace exactly as provided.
allow_empty (bool) – If True (default), allow empty strings to pass validation. Set to False to reject empty strings (after stripping if strip=True). For content validation, prefer chaining with non_empty_string() validator.
- Returns:
- Success(str) if input is a valid string, Failure(str) with
descriptive error message otherwise.
- Return type:
Examples
>>> parse_str("hello") Success('hello') >>> parse_str(" hello ") Success('hello') >>> parse_str(" hello ", strip=False) Success(' hello ') >>> parse_str("").is_success() True >>> parse_str("", allow_empty=False).is_failure() True >>> parse_str(None).is_failure() True >>> parse_str(42).is_failure() True >>> parse_str("hello").bind(lambda s: Maybe.success(s.upper())) Success('HELLO')
- Design Notes:
Strips whitespace by default (consistent with parse_int, parse_float)
Empty strings allowed by default (type validation, not content validation)
Use strip=False when whitespace is semantically meaningful
Chain with validators for content rules: parse_str(x).bind(non_empty_string())
No DoS protection needed (isinstance is O(1), no expensive operations)
- valid8r.core.parsers.parse_int(input_value, error_message=None)[source]
Parse a string to an integer.
Converts string representations of integers to Python int values. Handles whitespace trimming and accepts whole numbers in float notation (e.g., “42.0”).
- Parameters:
- Returns:
Success(int) if parsing succeeds, Failure(str) with error message otherwise
- Return type:
Examples
>>> parse_int("42") Success(42) >>> parse_int(" -17 ") Success(-17) >>> parse_int("42.0") Success(42) >>> parse_int("42.5").is_failure() True >>> parse_int("not a number").is_failure() True
- valid8r.core.parsers.parse_float(input_value, error_message=None)[source]
Parse a string to a floating-point number.
Converts string representations of numbers to Python float values. Handles whitespace trimming and scientific notation.
- Parameters:
- Returns:
Success(float) if parsing succeeds, Failure(str) with error message otherwise
- Return type:
Examples
>>> parse_float("3.14") Success(3.14) >>> parse_float(" -2.5 ") Success(-2.5) >>> parse_float("1e-3") Success(0.001) >>> parse_float("not a number").is_failure() True
- valid8r.core.parsers.parse_bool(input_value, error_message=None)[source]
Parse a string to a boolean value.
Accepts various common representations of true/false values. Case-insensitive and handles whitespace.
Recognized true values: ‘true’, ‘t’, ‘yes’, ‘y’, ‘1’ Recognized false values: ‘false’, ‘f’, ‘no’, ‘n’, ‘0’
- Parameters:
- Returns:
Success(bool) if parsing succeeds, Failure(str) with error message otherwise
- Return type:
Examples
>>> parse_bool("true") Success(True) >>> parse_bool("YES") Success(True) >>> parse_bool("n") Success(False) >>> parse_bool(" 0 ") Success(False) >>> parse_bool("maybe").is_failure() True
- valid8r.core.parsers.parse_date(input_value, date_format=None, error_message=None)[source]
Parse a string to a date object.
Parses date strings using ISO 8601 format (YYYY-MM-DD) by default, or a custom format if specified.
- Parameters:
- Returns:
Success(date) if parsing succeeds, Failure(str) with error message otherwise
- Return type:
Maybe[date]
Examples
>>> parse_date("2025-01-15") Success(datetime.date(2025, 1, 15)) >>> parse_date("01/15/2025", date_format="%m/%d/%Y") Success(datetime.date(2025, 1, 15)) >>> parse_date("invalid").is_failure() True
- valid8r.core.parsers.parse_datetime(input_value, error_message=None)[source]
Parse a string to a timezone-aware datetime object.
Parses datetime strings in ISO 8601 format with timezone information. Requires timezone to be specified (naive datetimes are rejected).
Supports: - Z suffix for UTC (e.g., ‘2024-01-01T12:00:00Z’) - Explicit UTC offset (e.g., ‘2024-01-01T12:00:00+00:00’) - Positive/negative timezone offsets (e.g., ‘2024-01-01T12:00:00+05:30’, ‘2024-01-01T12:00:00-08:00’) - Fractional seconds (e.g., ‘2024-01-01T12:00:00.123456Z’)
- Parameters:
- Returns:
- Success(datetime) if parsing succeeds with timezone info,
Failure(str) with error message otherwise
- Return type:
Maybe[datetime]
Examples
>>> parse_datetime("2024-01-01T12:00:00Z") Success(datetime.datetime(2024, 1, 1, 12, 0, tzinfo=datetime.timezone.utc)) >>> parse_datetime("2024-01-01T12:00:00+05:30") Success(datetime.datetime(2024, 1, 1, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=19800)))) >>> parse_datetime("2024-01-01T12:00:00").is_failure() True
- valid8r.core.parsers.parse_timedelta(input_value, error_message=None)[source]
Parse a string to a timedelta object.
Parses duration strings in multiple formats: - Simple format: ‘90m’, ‘2h’, ’45s’, ‘3d’ - Combined format: ‘1h 30m’, ‘1d 2h 30m 45s’, ‘1h30m’ (no spaces) - ISO 8601 duration: ‘PT1H30M’, ‘P1DT2H’, ‘PT45S’
Supported units: - d: days - h: hours - m: minutes - s: seconds
- Parameters:
- Returns:
- Success(timedelta) if parsing succeeds,
Failure(str) with error message otherwise
- Return type:
Maybe[timedelta]
Examples
>>> parse_timedelta("90m") Success(datetime.timedelta(seconds=5400)) >>> parse_timedelta("1h 30m") Success(datetime.timedelta(seconds=5400)) >>> parse_timedelta("PT1H30M") Success(datetime.timedelta(seconds=5400)) >>> parse_timedelta("-90m").is_failure() True
- valid8r.core.parsers.parse_complex(input_value, error_message=None)[source]
Parse a string to a complex number.
Accepts various complex number representations including both ‘j’ and ‘i’ notation. Handles parentheses and spaces in the input.
- Parameters:
- Returns:
Success(complex) if parsing succeeds, Failure(str) with error message otherwise
- Return type:
Examples
>>> parse_complex("3+4j") Success((3+4j)) >>> parse_complex("3 + 4i") Success((3+4j)) >>> parse_complex("(2-3j)") Success((2-3j)) >>> parse_complex("5j") Success(5j) >>> parse_complex("invalid").is_failure() True
- valid8r.core.parsers.parse_decimal(input_value, error_message=None)[source]
Parse a string to a Decimal for precise decimal arithmetic.
Uses Python’s Decimal type for arbitrary-precision decimal arithmetic, avoiding floating-point rounding errors. Ideal for financial calculations.
- Parameters:
- Returns:
Success with Decimal value or Failure with an error message
- Return type:
Maybe[Decimal]
Examples
>>> parse_decimal("3.14159") Success(Decimal('3.14159')) >>> parse_decimal(" 0.1 ") Success(Decimal('0.1')) >>> parse_decimal("-99.99") Success(Decimal('-99.99')) >>> parse_decimal("not a number").is_failure() True
- valid8r.core.parsers.parse_enum(input_value, enum_class, error_message=None)[source]
Parse a string to an enum member.
Matches input against enum member values and names (case-insensitive for names). Handles whitespace trimming and supports enums with empty string values.
- Parameters:
- Returns:
Success with enum member if valid, Failure(str) with error message otherwise
- Return type:
Examples
>>> from enum import Enum >>> class Color(Enum): ... RED = 'red' ... GREEN = 'green' ... BLUE = 'blue' >>> parse_enum("red", Color) Success(<Color.RED: 'red'>) >>> parse_enum("RED", Color) Success(<Color.RED: 'red'>) >>> parse_enum(" green ", Color) Success(<Color.GREEN: 'green'>) >>> parse_enum("yellow", Color).is_failure() True
- valid8r.core.parsers.parse_list(input_value, element_parser=None, separator=',', error_message=None)[source]
Parse a string to a list using the specified element parser and separator.
Splits the input string by the separator and parses each element using the element parser. If no element parser is provided, elements are returned as trimmed strings.
- Parameters:
input_value (str) – The string to parse
element_parser (collections.abc.Callable[[str], valid8r.core.maybe.Maybe[T]] | None) – A function that parses individual elements (default: strips whitespace)
separator (str) – The string that separates elements (default: ‘,’)
error_message (str | None) – Custom error message for parsing failures
- Returns:
Success with parsed list or Failure with error message
- Return type:
Examples
>>> parse_list("a,b,c") Success(['a', 'b', 'c']) >>> parse_list("1, 2, 3", element_parser=parse_int) Success([1, 2, 3]) >>> parse_list("apple|banana|cherry", separator="|") Success(['apple', 'banana', 'cherry']) >>> parse_list("1,2,invalid", element_parser=parse_int).is_failure() True
- valid8r.core.parsers.parse_dict(input_value, key_parser=None, value_parser=None, pair_separator=',', key_value_separator=':', error_message=None)[source]
Parse a string to a dictionary using the specified parsers and separators.
Splits the input string by pair_separator, then splits each pair by key_value_separator. Parses keys and values using the provided parsers (defaults to trimmed strings).
- Parameters:
input_value (str) – The string to parse
key_parser (collections.abc.Callable[[str], valid8r.core.maybe.Maybe[K]] | None) – A function that parses keys (default: strips whitespace)
value_parser (collections.abc.Callable[[str], valid8r.core.maybe.Maybe[V]] | None) – A function that parses values (default: strips whitespace)
pair_separator (str) – The string that separates key-value pairs (default: ‘,’)
key_value_separator (str) – The string that separates keys from values (default: ‘:’)
error_message (str | None) – Custom error message for parsing failures
- Returns:
Success with parsed dictionary or Failure with error message
- Return type:
Examples
>>> parse_dict("a:1,b:2,c:3") Success({'a': '1', 'b': '2', 'c': '3'}) >>> parse_dict("x:10, y:20", value_parser=parse_int) Success({'x': 10, 'y': 20}) >>> parse_dict("name=Alice|age=30", pair_separator="|", key_value_separator="=") Success({'name': 'Alice', 'age': '30'}) >>> parse_dict("a:1,b:invalid", value_parser=parse_int).is_failure() True
- valid8r.core.parsers.parse_set(input_value, element_parser=None, separator=None, error_message=None)[source]
Parse a string to a set using the specified element parser and separator.
Splits the input string by the separator and parses each element using the element parser. Automatically removes duplicate values. If no element parser is provided, elements are returned as trimmed strings.
- Parameters:
input_value (str) – The string to parse
element_parser (collections.abc.Callable[[str], valid8r.core.maybe.Maybe[T]] | None) – A function that parses individual elements (default: strips whitespace)
separator (str | None) – The string that separates elements (default: ‘,’)
error_message (str | None) – Custom error message for parsing failures
- Returns:
Success with parsed set or Failure with error message
- Return type:
Examples
>>> result = parse_set("a,b,c") >>> result.is_success() True >>> sorted(result.value_or(set())) ['a', 'b', 'c'] >>> result = parse_set("1, 2, 3, 2, 1", element_parser=parse_int) >>> sorted(result.value_or(set())) [1, 2, 3] >>> result = parse_set("red|blue|green|red", separator="|") >>> sorted(result.value_or(set())) ['blue', 'green', 'red'] >>> parse_set("1,2,invalid", element_parser=parse_int).is_failure() True
- valid8r.core.parsers.parse_int_with_validation(input_value, min_value=None, max_value=None, error_message=None)[source]
Parse a string to an integer with range validation.
Combines parsing and validation in a single step. First parses the string to an integer, then validates it falls within the specified range.
- Parameters:
- Returns:
Success with validated integer or Failure with error message
- Return type:
Examples
>>> parse_int_with_validation("42", min_value=0, max_value=100) Success(42) >>> parse_int_with_validation("5", min_value=10).is_failure() True >>> parse_int_with_validation("150", max_value=100).is_failure() True >>> parse_int_with_validation("50", min_value=0, max_value=100) Success(50)
- valid8r.core.parsers.parse_list_with_validation(input_value, element_parser=None, separator=',', min_length=None, max_length=None, error_message=None)[source]
Parse a string to a list with length validation.
Combines parsing and validation in a single step. First parses the string to a list, then validates it has an acceptable number of elements.
- Parameters:
input_value (str) – The string to parse
element_parser (collections.abc.Callable[[str], valid8r.core.maybe.Maybe[T]] | None) – A function that parses individual elements
separator (str) – The string that separates elements
min_length (int | None) – Minimum allowed list length
max_length (int | None) – Maximum allowed list length
error_message (str | None) – Custom error message for parsing failures
- Returns:
Success with validated list or Failure with error message
- Return type:
Examples
>>> parse_list_with_validation("a,b,c", min_length=2, max_length=5) Success(['a', 'b', 'c']) >>> parse_list_with_validation("1,2", element_parser=parse_int, min_length=3).is_failure() True >>> parse_list_with_validation("1,2,3,4,5,6", max_length=5).is_failure() True >>> parse_list_with_validation("10,20,30", element_parser=parse_int, min_length=1) Success([10, 20, 30])
- valid8r.core.parsers.parse_dict_with_validation(input_value, key_parser=None, value_parser=None, pair_separator=',', key_value_separator=':', required_keys=None, error_message=None)[source]
Parse a string to a dictionary with required keys validation.
Combines parsing and validation in a single step. First parses the string to a dictionary, then validates that all required keys are present.
- Parameters:
input_value (str) – The string to parse
key_parser (collections.abc.Callable[[str], valid8r.core.maybe.Maybe[K]] | None) – A function that parses keys
value_parser (collections.abc.Callable[[str], valid8r.core.maybe.Maybe[V]] | None) – A function that parses values
pair_separator (str) – The string that separates key-value pairs
key_value_separator (str) – The string that separates keys from values
required_keys (list[str] | None) – List of keys that must be present
error_message (str | None) – Custom error message for parsing failures
- Returns:
Success with validated dictionary or Failure with error message
- Return type:
Examples
>>> parse_dict_with_validation("name:Alice,age:30", required_keys=["name", "age"]) Success({'name': 'Alice', 'age': '30'}) >>> parse_dict_with_validation("name:Bob", required_keys=["name", "age"]).is_failure() True >>> result = parse_dict_with_validation("x:10,y:20", value_parser=parse_int, required_keys=["x"]) >>> result.value_or({}) {'x': 10, 'y': 20}
- valid8r.core.parsers.create_parser(convert_func, error_message=None)[source]
Create a parser function from a conversion function.
This factory takes a function that converts strings to values and wraps it in error handling logic to return Maybe instances.
- Parameters:
convert_func (collections.abc.Callable[[str], T]) – A function that converts strings to values of type T
error_message (str | None) – Optional custom error message for failures
- Returns:
A parser function that returns Maybe[T]
- Return type:
collections.abc.Callable[[str], valid8r.core.maybe.Maybe[T]]
Example
>>> from decimal import Decimal >>> parse_decimal = create_parser(Decimal, "Invalid decimal format") >>> result = parse_decimal("3.14") >>> result.is_success() True
- valid8r.core.parsers.make_parser(func: collections.abc.Callable[[str], T]) collections.abc.Callable[[str], valid8r.core.maybe.Maybe[T]][source]
- valid8r.core.parsers.make_parser() collections.abc.Callable[[collections.abc.Callable[[str], T]], collections.abc.Callable[[str], valid8r.core.maybe.Maybe[T]]]
Create a parser function from a conversion function with a decorator.
Example
@make_parser def parse_decimal(s: str) -> Decimal:
return Decimal(s)
# Or with parentheses @make_parser() def parse_decimal(s: str) -> Decimal:
return Decimal(s)
result = parse_decimal(“123.45”) # Returns Maybe[Decimal]
- valid8r.core.parsers.validated_parser(convert_func, validator, error_message=None)[source]
Create a parser with a built-in validator.
This combines parsing and validation in a single function.
- Parameters:
convert_func (collections.abc.Callable[[str], T]) – A function that converts strings to values of type T
validator (collections.abc.Callable[[T], valid8r.core.maybe.Maybe[T]]) – A validator function that validates the parsed value
error_message (str | None) – Optional custom error message for parsing failures
- Returns:
A parser function that returns Maybe[T]
- Return type:
collections.abc.Callable[[str], valid8r.core.maybe.Maybe[T]]
Example
>>> from decimal import Decimal >>> from valid8r.core.validators import minimum, maximum >>> # Create a parser for positive decimals >>> valid_range = lambda x: minimum(0)(x).bind(lambda y: maximum(100)(y)) >>> parse_percent = validated_parser(Decimal, valid_range) >>> result = parse_percent("42.5") >>> result.is_success() True
- valid8r.core.parsers.parse_uuid(text, version=None, strict=True)[source]
Parse a string to a UUID.
Uses uuid-utils to parse and validate UUIDs across versions 1, 3, 4, 5, 6, 7, and 8 when available. When
versionis provided, validates the parsed UUID version. Instrictmode (default), a mismatch yields a Failure; otherwise, the mismatch is ignored and the UUID is returned.- Parameters:
- Returns:
Success with a UUID object or Failure with an error message.
- Return type:
Maybe[UUID]
- valid8r.core.parsers.parse_ipv4(text)[source]
Parse an IPv4 address string.
Validates and parses IPv4 addresses in dotted-decimal notation. Trims surrounding whitespace.
- Parameters:
text (str) – String containing an IPv4 address (whitespace is stripped)
- Returns:
Success(IPv4Address) if valid, Failure(str) with error message otherwise
- Return type:
Maybe[IPv4Address]
Examples
>>> parse_ipv4("192.168.1.1") Success(IPv4Address('192.168.1.1')) >>> parse_ipv4(" 10.0.0.1 ") Success(IPv4Address('10.0.0.1')) >>> parse_ipv4("256.1.1.1").is_failure() True >>> parse_ipv4("not an ip").is_failure() True
- valid8r.core.parsers.parse_ipv6(text)[source]
Parse an IPv6 address string.
Validates and parses IPv6 addresses in standard notation. Rejects scope IDs (e.g., %eth0). Trims surrounding whitespace.
- Parameters:
text (str) – String containing an IPv6 address (whitespace is stripped)
- Returns:
Success(IPv6Address) if valid, Failure(str) with error message otherwise
- Return type:
Maybe[IPv6Address]
Examples
>>> parse_ipv6("::1") Success(IPv6Address('::1')) >>> parse_ipv6("2001:0db8:85a3::8a2e:0370:7334") Success(IPv6Address('2001:db8:85a3::8a2e:370:7334')) >>> parse_ipv6(" fe80::1 ") Success(IPv6Address('fe80::1')) >>> parse_ipv6("192.168.1.1").is_failure() True
- valid8r.core.parsers.parse_ip(text)[source]
Parse a string as either an IPv4 or IPv6 address.
Automatically detects and parses either IPv4 or IPv6 addresses. Trims surrounding whitespace.
- Parameters:
text (str) – String containing an IP address (IPv4 or IPv6, whitespace is stripped)
- Returns:
- Success with IPv4Address or IPv6Address if valid,
Failure(str) with error message otherwise
- Return type:
Maybe[IPv4Address | IPv6Address]
Examples
>>> result = parse_ip("192.168.1.1") >>> result.is_success() True >>> result = parse_ip("::1") >>> result.is_success() True >>> parse_ip(" 10.0.0.1 ") Success(IPv4Address('10.0.0.1')) >>> parse_ip("not an ip").is_failure() True
- valid8r.core.parsers.parse_cidr(text, *, strict=True)[source]
Parse a CIDR network string (IPv4 or IPv6).
Validates and parses network addresses in CIDR notation (e.g., 192.168.1.0/24). By default, validates that host bits are not set (strict mode). With strict=False, host bits are masked to the network address.
- Parameters:
- Returns:
- Success with IPv4Network or IPv6Network if valid,
Failure(str) with error message otherwise
- Return type:
Maybe[IPv4Network | IPv6Network]
Examples
>>> parse_cidr("192.168.1.0/24") Success(IPv4Network('192.168.1.0/24')) >>> parse_cidr("10.0.0.0/8") Success(IPv4Network('10.0.0.0/8')) >>> parse_cidr("2001:db8::/32") Success(IPv6Network('2001:db8::/32')) >>> # Strict mode rejects host bits >>> parse_cidr("192.168.1.5/24").is_failure() True >>> # Non-strict mode masks host bits >>> result = parse_cidr("192.168.1.5/24", strict=False) >>> str(result.value_or(None)) '192.168.1.0/24'
- class valid8r.core.parsers.UrlParts[source]
Structured URL components.
- host[source]
Lowercased host or IPv6 literal without brackets, or None when not provided and not required.
Examples
>>> from valid8r.core.maybe import Success >>> match parse_url('https://alice:pw@example.com:8443/x?q=1#top'): ... case Success(u): ... (u.scheme, u.username, u.password, u.host, u.port, u.path, u.query, u.fragment) ... case _: ... () ('https', 'alice', 'pw', 'example.com', 8443, '/x', 'q=1', 'top')
- class valid8r.core.parsers.EmailAddress[source]
Structured email address.
Examples
>>> from valid8r.core.maybe import Success >>> match parse_email('First.Last+tag@Example.COM'): ... case Success(addr): ... (addr.local, addr.domain) ... case _: ... () ('First.Last+tag', 'example.com')
- class valid8r.core.parsers.PhoneNumber[source]
Structured North American phone number (NANP).
Represents a parsed and validated phone number in the North American Numbering Plan (United States, Canada, and other NANP territories).
Examples
>>> from valid8r.core.maybe import Success >>> match parse_phone('(415) 555-2671'): ... case Success(phone): ... (phone.area_code, phone.exchange, phone.subscriber) ... case _: ... () ('415', '555', '2671')
- property e164: str[source]
E.164 international format (+14155552671).
The E.164 format is the international standard for phone numbers. It includes the country code prefix and no formatting separators.
- Returns:
Phone number in E.164 format, with extension if present.
- Return type:
- property national: str[source]
National format ((415) 555-2671).
The national format is the standard format for displaying phone numbers within a country, without the country code.
- Returns:
Phone number in national format, with extension if present.
- Return type:
- valid8r.core.parsers.parse_url(text, *, allowed_schemes=('http', 'https'), require_host=True)[source]
Parse a URL with light validation.
Rules: - Trim surrounding whitespace only - Require scheme in allowed_schemes (defaults to http/https) - If require_host, netloc must include a valid host (hostname, IPv4, or bracketed IPv6) - Lowercase scheme and host; do not modify path/query/fragment
Failure messages (exact substrings): - Input must be a string - Input must not be empty - Unsupported URL scheme - URL requires host - Invalid host
- Parameters:
text (str) – The URL string to parse
allowed_schemes (collections.abc.Iterable[str]) – Iterable of allowed scheme names (default: (‘http’, ‘https’))
require_host (bool) – Whether to require a host in the URL (default: True)
- Returns:
Success with UrlParts containing parsed components, or Failure with error message
- Return type:
Examples
>>> from valid8r.core.parsers import parse_url >>> from valid8r.core.maybe import Success >>> >>> # Parse a complete URL >>> result = parse_url('https://user:pass@api.example.com:8080/v1/users?active=true#section') >>> isinstance(result, Success) True >>> url = result.value >>> url.scheme 'https' >>> url.host 'api.example.com' >>> url.port 8080 >>> url.path '/v1/users' >>> url.query 'active=true' >>> url.fragment 'section' >>> >>> # Access credentials >>> url.username 'user' >>> url.password 'pass'
- valid8r.core.parsers.parse_email(text)[source]
Parse a bare email address of the form
local@domain.Uses the email-validator library for RFC 5322 compliant validation. Domain names are normalized to lowercase, local parts preserve their case.
Requires the email-validator library to be installed. If not available, returns a Failure indicating the library is required.
Rules: - Trim surrounding whitespace - Full RFC 5322 email validation - Supports internationalized domains (IDNA) - Domain is lowercased in the result; local part preserves case
Failure messages: - Input must be a string - Input must not be empty - email-validator library is required but not installed - Various RFC-compliant validation error messages from email-validator
- Parameters:
text (str) – The email address string to parse
- Returns:
Success with EmailAddress or Failure with error message
- Return type:
Examples
>>> from valid8r.core.parsers import parse_email >>> from valid8r.core.maybe import Success >>> >>> # Parse an email with case normalization >>> result = parse_email('User.Name+tag@Example.COM') >>> isinstance(result, Success) True >>> email = result.value >>> # Local part preserves original case >>> email.local 'User.Name+tag' >>> # Domain is normalized to lowercase >>> email.domain 'example.com'
- valid8r.core.parsers.parse_phone(text, *, region='US', strict=False)[source]
Parse a North American phone number (NANP format).
Parses phone numbers in the North American Numbering Plan format (US, Canada, etc.). Supports various formatting styles and validates area codes and exchanges.
Rules: - Accepts 10-digit or 11-digit (with country code 1) phone numbers - Strips all non-digit characters except extension markers - Validates area code (NPA): cannot start with 0 or 1, cannot be 555 - Validates exchange (NXX): cannot start with 0 or 1, cannot be 555 or 911 - Supports extensions with markers: x, ext, extension, comma - In strict mode, requires formatting characters (not just digits) - Defaults to US region unless specified
Failure messages: - Phone number cannot be empty - Phone number must have exactly 10 digits (after country code) - Invalid area code (starts with 0/1 or reserved) - Invalid exchange (starts with 0/1, reserved, or emergency) - Only North American phone numbers are supported - Invalid format (contains non-digit/non-separator characters) - Strict mode requires formatting characters - Invalid extension (non-numeric or too long)
- Parameters:
- Returns:
Success with PhoneNumber or Failure with error message
- Return type:
Examples
>>> match parse_phone('(415) 555-2671'): ... case Success(phone): ... phone.area_code ... case _: ... None '415'
>>> match parse_phone('415-555-2671 x123'): ... case Success(phone): ... phone.extension ... case _: ... None '123'
>>> match parse_phone('+1 604 555 1234', region='CA'): ... case Success(phone): ... phone.region ... case _: ... None 'CA'
- valid8r.core.parsers.parse_slug(text, *, min_length=None, max_length=None)[source]
Parse a URL-safe slug (lowercase letters, numbers, hyphens only).
A valid slug contains only lowercase letters, numbers, and hyphens. Cannot start/end with hyphen or have consecutive hyphens.
- Parameters:
- Returns:
Success with slug or Failure with error
- Return type:
Examples
>>> from valid8r.core.parsers import parse_slug >>> >>> # Valid slugs >>> parse_slug('hello-world').value_or(None) 'hello-world' >>> parse_slug('blog-post-123').value_or(None) 'blog-post-123' >>> parse_slug('a').value_or(None) 'a' >>> >>> # With length constraints >>> parse_slug('hello', min_length=5).value_or(None) 'hello' >>> parse_slug('hello', max_length=10).value_or(None) 'hello' >>> >>> # Invalid slugs >>> parse_slug('').is_failure() True >>> parse_slug('Hello-World').is_failure() True >>> parse_slug('hello_world').is_failure() True >>> parse_slug('-hello').is_failure() True >>> parse_slug('hello-').is_failure() True >>> parse_slug('hello--world').is_failure() True >>> >>> # Length constraint failures >>> parse_slug('hi', min_length=5).is_failure() True >>> parse_slug('very-long-slug', max_length=5).is_failure() True
- valid8r.core.parsers.parse_json(text)[source]
Parse a JSON string into a Python object.
Supports all JSON types: objects, arrays, strings, numbers, booleans, null.
- Parameters:
text (str) – JSON-formatted string
- Returns:
Success with parsed object or Failure with error
- Return type:
Examples
>>> from valid8r.core.parsers import parse_json >>> >>> # JSON objects >>> parse_json('{"name": "Alice", "age": 30}').value_or(None) {'name': 'Alice', 'age': 30} >>> >>> # JSON arrays >>> parse_json('[1, 2, 3, 4, 5]').value_or(None) [1, 2, 3, 4, 5] >>> >>> # JSON primitives >>> parse_json('"hello world"').value_or(None) 'hello world' >>> parse_json('42').value_or(None) 42 >>> parse_json('true').value_or(None) True >>> parse_json('false').value_or(None) False >>> parse_json('null').value_or(None) >>> >>> # Invalid JSON >>> parse_json('').is_failure() True >>> parse_json('{invalid}').is_failure() True >>> parse_json('{"name": "Alice"').is_failure() True
- valid8r.core.parsers.parse_base64(text)[source]
Parse and decode a base64-encoded string.
Accepts both standard and URL-safe base64, with or without padding. Handles whitespace and newlines within the base64 string.
- Parameters:
text (str) – Base64-encoded string
- Returns:
Success with decoded bytes or Failure with error
- Return type:
Examples
>>> from valid8r.core.parsers import parse_base64 >>> >>> # Standard base64 with padding >>> parse_base64('SGVsbG8gV29ybGQ=').value_or(None) b'Hello World' >>> >>> # Standard base64 without padding >>> parse_base64('SGVsbG8gV29ybGQ').value_or(None) b'Hello World' >>> >>> # URL-safe base64 (hyphens and underscores) >>> parse_base64('A-A=').is_success() True >>> parse_base64('Pz8_').is_success() True >>> >>> # Base64 with whitespace (automatically stripped) >>> parse_base64(' SGVsbG8gV29ybGQ= ').value_or(None) b'Hello World' >>> >>> # Invalid base64 >>> parse_base64('').is_failure() True >>> parse_base64('Not@Valid!').is_failure() True >>> parse_base64('====').is_failure() True
- valid8r.core.parsers.parse_jwt(text)[source]
Parse and validate a JWT (JSON Web Token) structure.
Validates that the JWT has exactly three parts (header.payload.signature) separated by dots, and that each part is valid base64url. Also validates that header and payload are valid JSON.
Note: This function validates JWT structure only. It does NOT verify the cryptographic signature. Use a dedicated JWT library (e.g., PyJWT) for signature verification and claims validation.
- Parameters:
text (str) – JWT string to validate
- Returns:
Success with original JWT or Failure with error
- Return type:
Examples
>>> from valid8r.core.parsers import parse_jwt >>> >>> # Valid JWT (structure only - signature not verified) >>> jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.sig' >>> parse_jwt(jwt).is_success() True >>> >>> # JWT with whitespace (automatically stripped) >>> parse_jwt(' ' + jwt + ' ').is_success() True >>> >>> # Invalid: empty string >>> parse_jwt('').is_failure() True >>> >>> # Invalid: wrong number of parts >>> parse_jwt('header.payload').is_failure() True >>> parse_jwt('a.b.c.d').is_failure() True >>> >>> # Invalid: non-base64url encoding >>> parse_jwt('not-base64!.eyJzdWIiOiIxMjM0In0.sig').is_failure() True >>> >>> # Invalid: non-JSON header/payload >>> parse_jwt('bm90anNvbg==.eyJzdWIiOiIxMjM0In0.sig').is_failure() True
- valid8r.core.parsers.parse_path(text, *, expand_user=False, resolve=False, error_message=None)[source]
Parse a string into a pathlib.Path object.
Converts string representations of filesystem paths to Python Path objects. Handles cross-platform path formats, optional home directory expansion, and optional resolution to absolute paths.
- Parameters:
text (str | None) – The path string to parse (leading/trailing whitespace is stripped)
expand_user (bool) – If True, expand ~ to user’s home directory (default: False)
resolve (bool) – If True, resolve to absolute path following symlinks (default: False)
error_message (str | None) – Custom error message for invalid input (optional)
- Returns:
Success(Path) if parsing succeeds, Failure(str) with error message otherwise
- Return type:
Maybe[Path]
Examples
>>> parse_path('/home/user/file.txt') Success(PosixPath('/home/user/file.txt')) >>> parse_path('data/file.txt') Success(PosixPath('data/file.txt')) >>> parse_path('') Failure('Path cannot be empty') >>> parse_path(None) Failure('Path cannot be empty')
Notes
Path normalization (collapsing redundant separators) happens automatically
This parser does NOT validate path existence - use validators for that
Use expand_user=True to expand ~ to the user’s home directory
Use resolve=True to convert relative paths to absolute paths
The resolve option will follow symlinks and normalize the path
Input length is limited to 4096 characters to prevent DoS attacks