dict-patterns


Namedict-patterns JSON
Version 0.2.1 PyPI version JSON
download
home_pageNone
SummaryA template engine for dictionary data – useful for tests!
upload_time2025-08-30 17:46:46
maintainerAntonio Feregrino
docs_urlNone
authorAntonio Feregrino
requires_python>=3.10
licenseMIT
keywords dictionary pattern-matching template-engine testing validation json regex pytest data-validation
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Dictionary Patterns

A template engine for data in dictionaries – useful for tests!

## Overview

Dictionary Patterns is a Python library that allows you to match dictionary objects using pattern-based templates. It's particularly useful for testing scenarios where you need to verify that dictionary responses match expected patterns while allowing for dynamic values.

## Features

- **Pattern-based matching**: Use placeholders like `{string:name}` to match dynamic values
- **Value consistency**: Ensure the same pattern identifier has consistent values across matches
- **Nested structure support**: Handle complex nested dictionary objects and arrays
- **Partial matching**: Allow actual dictionaries to contain extra fields not present in the template
- **Custom exceptions**: Rich error handling with specific exception types
- **Flexible patterns**: Define your own regex patterns for different data types

## When to Use This Library

**This library does not replace JSON Schema validation.** It's designed for different use cases:

- **String-based pattern matching**: This library works exclusively with string values and regex patterns, making it ideal for validating string-based data structures
- **Non-deterministic outputs**: Perfect for testing APIs or functions that return dynamic data where exact values aren't predictable but patterns are known
- **Repeating value validation**: Useful when the same values can appear multiple times across a document and you need to ensure consistency
- **Simple validation scenarios**: Great for lightweight testing where full JSON Schema validation might be overkill

For complex data validation, type checking, or when you need to validate non-string data types, consider using JSON Schema or other validation libraries too.

## Installation

```bash
pip install dict-patterns
```

## Quick Start

```python
from dict_patterns import DictMatcher

# Define your patterns
patterns = {
    'string': r'[a-zA-Z]+',
    'number': r'\d+',
    'uuid': r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
}

# Create a matcher
matcher = DictMatcher(patterns)

# Define your template with placeholders
template = {
    'user': {
        'name': '{string:user_name}',
        'age': '{number:user_age}',
        'id': '{uuid:user_id}'
    }
}

# Your actual data
actual = {
    'user': {
        'name': 'John',
        'age': '25',
        'id': '1d408610-f129-47a8-a4c1-1a6e0ca2d16f'
    }
}

# Match them
matcher.match(template, actual)

# Access matched values
print(matcher.values['string']['user_name'])  # 'John'
print(matcher.values['number']['user_age'])   # '25'
print(matcher.values['uuid']['user_id'])      # '1d408610-f129-47a8-a4c1-1a6e0ca2d16f'

# Partial matching example
actual_with_extra = {
    'user': {
        'name': 'John',
        'age': '25',
        'id': '1d408610-f129-47a8-a4c1-1a6e0ca2d16f',
        'email': 'john@example.com',  # Extra field
        'address': {'street': '123 Main St'}  # Extra nested field
    }
}

# This will work with partial matching
matcher.match(template, actual_with_extra, partial_match=True)
```

## Pattern Syntax

Patterns use the format `{pattern_name:identifier}` where:

- `pattern_name` is the type of pattern to match (must be defined in your patterns dict)
- `identifier` is an optional name for the captured value (used for consistency checking)

### Examples

```python
# Simple patterns
'{string:name}'           # Matches alphabetic strings
'{number:age}'            # Matches numeric strings
'{uuid:user_id}'          # Matches UUID format

# Patterns without identifiers (no consistency checking)
'{string}'                # Matches any string, no identifier
'{number}'                # Matches any number, no identifier
```

Note that in the above example, the the patterns `string`, `number` and `uuid` must be previously defined.

## Error Handling

The library provides custom exceptions for better error handling and debugging:

### Exception Hierarchy

```
DictPatternError (base)
├── DictStructureError
│   ├── DictKeyMismatchError
│   └── DictListLengthMismatchError
├── DictValueMismatchError
├── DictPatternMatchError
├── DictPatternValueInconsistencyError
└── DictPatternTypeError
```

### Example Error Handling

```python
from dict_patterns import (
    DictMatcher,
    DictPatternError,
    DictStructureError,
    DictKeyMismatchError,
    DictPatternMatchError
)

try:
    matcher = DictMatcher({'email': r'[^@]+@[^@]+\.[^@]+'})
    template = {'email': '{email:user_email}'}
    actual = {'email': 'invalid-email'}
    matcher.match(template, actual)
except DictPatternMatchError as e:
    print(f"Pattern match failed at {e.path}")
    print(f"Expected pattern: {e.template}")
    print(f"Actual value: {e.actual}")
except DictStructureError as e:
    print(f"Structure mismatch: {e}")
except DictPatternError as e:
    print(f"Any dictionary pattern error: {e}")
```

### Exception Types

- **`DictKeyMismatchError`**: Dictionary keys don't match between template and actual
- **`DictListLengthMismatchError`**: Lists have different lengths
- **`DictValueMismatchError`**: Simple values don't match (with optional template/actual values)
- **`DictPatternMatchError`**: String doesn't match the pattern template
- **`DictPatternValueInconsistencyError`**: Same pattern identifier has different values
- **`DictPatternTypeError`**: Unknown pattern type encountered

## Advanced Usage

### Partial Matching

When you need to match against dictionaries that may contain additional fields not present in your template, you can use partial matching:

```python
template = {
    'user': {
        'name': '{string:user_name}',
        'age': '{number:user_age}'
    }
}

# This actual data has extra fields
actual = {
    'user': {
        'name': 'John',
        'age': '25',
        'email': 'john@example.com',  # Extra field
        'address': {'street': '123 Main St'}  # Extra nested field
    },
    'metadata': {'version': '1.0'}  # Extra field at root level
}

# Use partial_match=True to allow extra fields
matcher.match(template, actual, partial_match=True)
```

**Key points about partial matching:**

- Only allows extra fields in the actual dictionary
- Template fields must still be present in the actual dictionary
- Works with nested structures at any level
- Pattern matching and value consistency still apply to matched fields

### Value Consistency

The library ensures that the same pattern identifier has consistent values across matches:

```python
template = {
    'parent_id': '{uuid:shared_id}',
    'child': {'parent_id': '{uuid:shared_id}'}  # Same identifier
}

actual = {
    'parent_id': '1d408610-f129-47a8-a4c1-1a6e0ca2d16f',
    'child': {'parent_id': '1d408610-f129-47a8-a4c1-1a6e0ca2d16f'}  # Same value
}

# This will work
matcher.match(template, actual)

# This will raise DictPatternValueInconsistencyError
actual['child']['parent_id'] = 'different-uuid'
matcher.match(template, actual)
```

### Complex Nested Structures

```python
template = {
    'users': [
        {'name': '{string}', 'email': '{email}'},
        {'name': '{string}', 'email': '{email}'}
    ],
    'metadata': {
        'total': '{number:total_count}',
        'created_at': '{timestamp:creation_time}'
    }
}
```

### Custom Patterns

```python
# Define your own patterns
patterns = {
    'string': r'[a-zA-Z]+',
    'number': r'\d+',
    'email': r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
    'phone': r'\+?1?\d{9,15}',
    'timestamp': r'\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z',
    'slug': r'[a-z0-9]+(?:-[a-z0-9]+)*'
}
```

## API Reference

### DictMatcher

The main class for matching dictionary objects.

#### Constructor

```python
DictMatcher(pattern_handlers: dict)
```

- `pattern_handlers`: Dictionary mapping pattern names to regex patterns

#### Methods

- `match(template: dict, actual: dict, partial_match: bool = False)`: Match template against actual dictionary
- `values`: Property containing matched values organized by pattern type

#### Parameters

- `template`: The template dictionary that may contain pattern placeholders
- `actual`: The actual dictionary to match against
- `partial_match`: When `True`, allows the actual dictionary to contain extra fields not present in the template


## Pytest Plugin

Dictionary Patterns includes a pytest plugin that provides convenient fixtures for testing. The plugin automatically registers when you install the package.

### Available Fixtures

#### `pattern_handlers`

Provides an empty dictionary for regex pattern definitions. Override this fixture in your tests to define custom patterns:

```python
import pytest

class TestWithCustomPatterns:
    @pytest.fixture
    def pattern_handlers(self):
        return {
            "string": r"[a-zA-Z]+",
            "number": r"\d+",
            "email": r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}",
        }
```

#### `dict_matcher`

Provides a `DictMatcher` instance configured with the pattern handlers from the `pattern_handlers` fixture:

```python
def test_basic_matching(dict_matcher):
    template = {"name": "{string:name}", "age": "{number:age}"}
    actual = {"name": "John", "age": "25"}
    
    dict_matcher.match(template, actual)
    
    assert dict_matcher.values["string"]["name"] == "John"
    assert dict_matcher.values["number"]["age"] == "25"
```

#### `dict_match`

Provides a convenience function that performs pattern matching and returns the extracted values:

```python
def test_convenience_matching(dict_match):
    template = {"name": "{string:name}", "age": "{number:age}"}
    actual = {"name": "John", "age": "25"}
    
    extracted_values = dict_match(template, actual)
    
    assert extracted_values == {
        "string": {"name": "John"},
        "number": {"age": "25"},
    }

def test_partial_matching(dict_match):
    template = {"name": "{string:name}", "age": "{number:age}"}
    actual = {"name": "John", "age": "25", "email": "john@example.com"}
    
    extracted_values = dict_match(template, actual, partial_match=True)
    
    assert extracted_values == {
        "string": {"name": "John"},
        "number": {"age": "25"},
    }
```

### Complete Example

```python
import pytest

class TestUserAPI:
    @pytest.fixture
    def pattern_handlers(self):
        return {
            "string": r"[a-zA-Z]+",
            "number": r"\d+",
            "uuid": r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
        }
    
    def test_user_response_structure(self, dict_match):
        # API response template
        template = {
            "user": {
                "id": "{uuid:user_id}",
                "name": "{string:user_name}",
                "age": "{number:user_age}",
            },
            "created_at": "{string:timestamp}",
        }
        
        # Actual API response
        actual = {
            "user": {
                "id": "1d408610-f129-47a8-a4c1-1a6e0ca2d16f",
                "name": "John Doe",
                "age": "30",
            },
            "created_at": "2024-01-15T10:30:00Z",
        }
        
        # Extract and verify values
        extracted = dict_match(template, actual)
        
        assert extracted["uuid"]["user_id"] == "1d408610-f129-47a8-a4c1-1a6e0ca2d16f"
        assert extracted["string"]["user_name"] == "John Doe"
        assert extracted["number"]["user_age"] == "30"
        assert extracted["string"]["timestamp"] == "2024-01-15T10:30:00Z"
```

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

This project is licensed under the MIT License.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "dict-patterns",
    "maintainer": "Antonio Feregrino",
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": "Antonio Feregrino <antonio.feregrino@gmail.com>",
    "keywords": "dictionary, pattern-matching, template-engine, testing, validation, json, regex, pytest, data-validation",
    "author": "Antonio Feregrino",
    "author_email": "Antonio Feregrino <antonio.feregrino@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/d1/97/ce56531aec3eec5a69dcc71b53a0369d6a9b88c45e0d77970e0396c1767d/dict_patterns-0.2.1.tar.gz",
    "platform": null,
    "description": "# Dictionary Patterns\n\nA template engine for data in dictionaries \u2013 useful for tests!\n\n## Overview\n\nDictionary Patterns is a Python library that allows you to match dictionary objects using pattern-based templates. It's particularly useful for testing scenarios where you need to verify that dictionary responses match expected patterns while allowing for dynamic values.\n\n## Features\n\n- **Pattern-based matching**: Use placeholders like `{string:name}` to match dynamic values\n- **Value consistency**: Ensure the same pattern identifier has consistent values across matches\n- **Nested structure support**: Handle complex nested dictionary objects and arrays\n- **Partial matching**: Allow actual dictionaries to contain extra fields not present in the template\n- **Custom exceptions**: Rich error handling with specific exception types\n- **Flexible patterns**: Define your own regex patterns for different data types\n\n## When to Use This Library\n\n**This library does not replace JSON Schema validation.** It's designed for different use cases:\n\n- **String-based pattern matching**: This library works exclusively with string values and regex patterns, making it ideal for validating string-based data structures\n- **Non-deterministic outputs**: Perfect for testing APIs or functions that return dynamic data where exact values aren't predictable but patterns are known\n- **Repeating value validation**: Useful when the same values can appear multiple times across a document and you need to ensure consistency\n- **Simple validation scenarios**: Great for lightweight testing where full JSON Schema validation might be overkill\n\nFor complex data validation, type checking, or when you need to validate non-string data types, consider using JSON Schema or other validation libraries too.\n\n## Installation\n\n```bash\npip install dict-patterns\n```\n\n## Quick Start\n\n```python\nfrom dict_patterns import DictMatcher\n\n# Define your patterns\npatterns = {\n    'string': r'[a-zA-Z]+',\n    'number': r'\\d+',\n    'uuid': r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'\n}\n\n# Create a matcher\nmatcher = DictMatcher(patterns)\n\n# Define your template with placeholders\ntemplate = {\n    'user': {\n        'name': '{string:user_name}',\n        'age': '{number:user_age}',\n        'id': '{uuid:user_id}'\n    }\n}\n\n# Your actual data\nactual = {\n    'user': {\n        'name': 'John',\n        'age': '25',\n        'id': '1d408610-f129-47a8-a4c1-1a6e0ca2d16f'\n    }\n}\n\n# Match them\nmatcher.match(template, actual)\n\n# Access matched values\nprint(matcher.values['string']['user_name'])  # 'John'\nprint(matcher.values['number']['user_age'])   # '25'\nprint(matcher.values['uuid']['user_id'])      # '1d408610-f129-47a8-a4c1-1a6e0ca2d16f'\n\n# Partial matching example\nactual_with_extra = {\n    'user': {\n        'name': 'John',\n        'age': '25',\n        'id': '1d408610-f129-47a8-a4c1-1a6e0ca2d16f',\n        'email': 'john@example.com',  # Extra field\n        'address': {'street': '123 Main St'}  # Extra nested field\n    }\n}\n\n# This will work with partial matching\nmatcher.match(template, actual_with_extra, partial_match=True)\n```\n\n## Pattern Syntax\n\nPatterns use the format `{pattern_name:identifier}` where:\n\n- `pattern_name` is the type of pattern to match (must be defined in your patterns dict)\n- `identifier` is an optional name for the captured value (used for consistency checking)\n\n### Examples\n\n```python\n# Simple patterns\n'{string:name}'           # Matches alphabetic strings\n'{number:age}'            # Matches numeric strings\n'{uuid:user_id}'          # Matches UUID format\n\n# Patterns without identifiers (no consistency checking)\n'{string}'                # Matches any string, no identifier\n'{number}'                # Matches any number, no identifier\n```\n\nNote that in the above example, the the patterns `string`, `number` and `uuid` must be previously defined.\n\n## Error Handling\n\nThe library provides custom exceptions for better error handling and debugging:\n\n### Exception Hierarchy\n\n```\nDictPatternError (base)\n\u251c\u2500\u2500 DictStructureError\n\u2502   \u251c\u2500\u2500 DictKeyMismatchError\n\u2502   \u2514\u2500\u2500 DictListLengthMismatchError\n\u251c\u2500\u2500 DictValueMismatchError\n\u251c\u2500\u2500 DictPatternMatchError\n\u251c\u2500\u2500 DictPatternValueInconsistencyError\n\u2514\u2500\u2500 DictPatternTypeError\n```\n\n### Example Error Handling\n\n```python\nfrom dict_patterns import (\n    DictMatcher,\n    DictPatternError,\n    DictStructureError,\n    DictKeyMismatchError,\n    DictPatternMatchError\n)\n\ntry:\n    matcher = DictMatcher({'email': r'[^@]+@[^@]+\\.[^@]+'})\n    template = {'email': '{email:user_email}'}\n    actual = {'email': 'invalid-email'}\n    matcher.match(template, actual)\nexcept DictPatternMatchError as e:\n    print(f\"Pattern match failed at {e.path}\")\n    print(f\"Expected pattern: {e.template}\")\n    print(f\"Actual value: {e.actual}\")\nexcept DictStructureError as e:\n    print(f\"Structure mismatch: {e}\")\nexcept DictPatternError as e:\n    print(f\"Any dictionary pattern error: {e}\")\n```\n\n### Exception Types\n\n- **`DictKeyMismatchError`**: Dictionary keys don't match between template and actual\n- **`DictListLengthMismatchError`**: Lists have different lengths\n- **`DictValueMismatchError`**: Simple values don't match (with optional template/actual values)\n- **`DictPatternMatchError`**: String doesn't match the pattern template\n- **`DictPatternValueInconsistencyError`**: Same pattern identifier has different values\n- **`DictPatternTypeError`**: Unknown pattern type encountered\n\n## Advanced Usage\n\n### Partial Matching\n\nWhen you need to match against dictionaries that may contain additional fields not present in your template, you can use partial matching:\n\n```python\ntemplate = {\n    'user': {\n        'name': '{string:user_name}',\n        'age': '{number:user_age}'\n    }\n}\n\n# This actual data has extra fields\nactual = {\n    'user': {\n        'name': 'John',\n        'age': '25',\n        'email': 'john@example.com',  # Extra field\n        'address': {'street': '123 Main St'}  # Extra nested field\n    },\n    'metadata': {'version': '1.0'}  # Extra field at root level\n}\n\n# Use partial_match=True to allow extra fields\nmatcher.match(template, actual, partial_match=True)\n```\n\n**Key points about partial matching:**\n\n- Only allows extra fields in the actual dictionary\n- Template fields must still be present in the actual dictionary\n- Works with nested structures at any level\n- Pattern matching and value consistency still apply to matched fields\n\n### Value Consistency\n\nThe library ensures that the same pattern identifier has consistent values across matches:\n\n```python\ntemplate = {\n    'parent_id': '{uuid:shared_id}',\n    'child': {'parent_id': '{uuid:shared_id}'}  # Same identifier\n}\n\nactual = {\n    'parent_id': '1d408610-f129-47a8-a4c1-1a6e0ca2d16f',\n    'child': {'parent_id': '1d408610-f129-47a8-a4c1-1a6e0ca2d16f'}  # Same value\n}\n\n# This will work\nmatcher.match(template, actual)\n\n# This will raise DictPatternValueInconsistencyError\nactual['child']['parent_id'] = 'different-uuid'\nmatcher.match(template, actual)\n```\n\n### Complex Nested Structures\n\n```python\ntemplate = {\n    'users': [\n        {'name': '{string}', 'email': '{email}'},\n        {'name': '{string}', 'email': '{email}'}\n    ],\n    'metadata': {\n        'total': '{number:total_count}',\n        'created_at': '{timestamp:creation_time}'\n    }\n}\n```\n\n### Custom Patterns\n\n```python\n# Define your own patterns\npatterns = {\n    'string': r'[a-zA-Z]+',\n    'number': r'\\d+',\n    'email': r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}',\n    'phone': r'\\+?1?\\d{9,15}',\n    'timestamp': r'\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z',\n    'slug': r'[a-z0-9]+(?:-[a-z0-9]+)*'\n}\n```\n\n## API Reference\n\n### DictMatcher\n\nThe main class for matching dictionary objects.\n\n#### Constructor\n\n```python\nDictMatcher(pattern_handlers: dict)\n```\n\n- `pattern_handlers`: Dictionary mapping pattern names to regex patterns\n\n#### Methods\n\n- `match(template: dict, actual: dict, partial_match: bool = False)`: Match template against actual dictionary\n- `values`: Property containing matched values organized by pattern type\n\n#### Parameters\n\n- `template`: The template dictionary that may contain pattern placeholders\n- `actual`: The actual dictionary to match against\n- `partial_match`: When `True`, allows the actual dictionary to contain extra fields not present in the template\n\n\n## Pytest Plugin\n\nDictionary Patterns includes a pytest plugin that provides convenient fixtures for testing. The plugin automatically registers when you install the package.\n\n### Available Fixtures\n\n#### `pattern_handlers`\n\nProvides an empty dictionary for regex pattern definitions. Override this fixture in your tests to define custom patterns:\n\n```python\nimport pytest\n\nclass TestWithCustomPatterns:\n    @pytest.fixture\n    def pattern_handlers(self):\n        return {\n            \"string\": r\"[a-zA-Z]+\",\n            \"number\": r\"\\d+\",\n            \"email\": r\"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\",\n        }\n```\n\n#### `dict_matcher`\n\nProvides a `DictMatcher` instance configured with the pattern handlers from the `pattern_handlers` fixture:\n\n```python\ndef test_basic_matching(dict_matcher):\n    template = {\"name\": \"{string:name}\", \"age\": \"{number:age}\"}\n    actual = {\"name\": \"John\", \"age\": \"25\"}\n    \n    dict_matcher.match(template, actual)\n    \n    assert dict_matcher.values[\"string\"][\"name\"] == \"John\"\n    assert dict_matcher.values[\"number\"][\"age\"] == \"25\"\n```\n\n#### `dict_match`\n\nProvides a convenience function that performs pattern matching and returns the extracted values:\n\n```python\ndef test_convenience_matching(dict_match):\n    template = {\"name\": \"{string:name}\", \"age\": \"{number:age}\"}\n    actual = {\"name\": \"John\", \"age\": \"25\"}\n    \n    extracted_values = dict_match(template, actual)\n    \n    assert extracted_values == {\n        \"string\": {\"name\": \"John\"},\n        \"number\": {\"age\": \"25\"},\n    }\n\ndef test_partial_matching(dict_match):\n    template = {\"name\": \"{string:name}\", \"age\": \"{number:age}\"}\n    actual = {\"name\": \"John\", \"age\": \"25\", \"email\": \"john@example.com\"}\n    \n    extracted_values = dict_match(template, actual, partial_match=True)\n    \n    assert extracted_values == {\n        \"string\": {\"name\": \"John\"},\n        \"number\": {\"age\": \"25\"},\n    }\n```\n\n### Complete Example\n\n```python\nimport pytest\n\nclass TestUserAPI:\n    @pytest.fixture\n    def pattern_handlers(self):\n        return {\n            \"string\": r\"[a-zA-Z]+\",\n            \"number\": r\"\\d+\",\n            \"uuid\": r\"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\",\n        }\n    \n    def test_user_response_structure(self, dict_match):\n        # API response template\n        template = {\n            \"user\": {\n                \"id\": \"{uuid:user_id}\",\n                \"name\": \"{string:user_name}\",\n                \"age\": \"{number:user_age}\",\n            },\n            \"created_at\": \"{string:timestamp}\",\n        }\n        \n        # Actual API response\n        actual = {\n            \"user\": {\n                \"id\": \"1d408610-f129-47a8-a4c1-1a6e0ca2d16f\",\n                \"name\": \"John Doe\",\n                \"age\": \"30\",\n            },\n            \"created_at\": \"2024-01-15T10:30:00Z\",\n        }\n        \n        # Extract and verify values\n        extracted = dict_match(template, actual)\n        \n        assert extracted[\"uuid\"][\"user_id\"] == \"1d408610-f129-47a8-a4c1-1a6e0ca2d16f\"\n        assert extracted[\"string\"][\"user_name\"] == \"John Doe\"\n        assert extracted[\"number\"][\"user_age\"] == \"30\"\n        assert extracted[\"string\"][\"timestamp\"] == \"2024-01-15T10:30:00Z\"\n```\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## License\n\nThis project is licensed under the MIT License.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A template engine for dictionary data \u2013 useful for tests!",
    "version": "0.2.1",
    "project_urls": {
        "Homepage": "https://github.com/fferegrino/dict-patterns",
        "Issues": "https://github.com/fferegrino/dict-patterns/issues",
        "Repository": "https://github.com/fferegrino/dict-patterns.git"
    },
    "split_keywords": [
        "dictionary",
        " pattern-matching",
        " template-engine",
        " testing",
        " validation",
        " json",
        " regex",
        " pytest",
        " data-validation"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "d164db8de611143e5b6f61c9898e09419a57080051f3e86517c7eeb5c736f3e6",
                "md5": "803cd8083f2372a580fe4a8695788352",
                "sha256": "ed27264f645ad9c2e7822249195c24aade5cc2883bb07b9a9c7ed816ce946acf"
            },
            "downloads": -1,
            "filename": "dict_patterns-0.2.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "803cd8083f2372a580fe4a8695788352",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 11965,
            "upload_time": "2025-08-30T17:46:45",
            "upload_time_iso_8601": "2025-08-30T17:46:45.810589Z",
            "url": "https://files.pythonhosted.org/packages/d1/64/db8de611143e5b6f61c9898e09419a57080051f3e86517c7eeb5c736f3e6/dict_patterns-0.2.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "d197ce56531aec3eec5a69dcc71b53a0369d6a9b88c45e0d77970e0396c1767d",
                "md5": "b40cde937089e8c95ccf76cf55a8c19f",
                "sha256": "de7d71cebf14542703b24c966f15f65d1be7ce191bb168e7747a5158e903ba1e"
            },
            "downloads": -1,
            "filename": "dict_patterns-0.2.1.tar.gz",
            "has_sig": false,
            "md5_digest": "b40cde937089e8c95ccf76cf55a8c19f",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 10218,
            "upload_time": "2025-08-30T17:46:46",
            "upload_time_iso_8601": "2025-08-30T17:46:46.909002Z",
            "url": "https://files.pythonhosted.org/packages/d1/97/ce56531aec3eec5a69dcc71b53a0369d6a9b88c45e0d77970e0396c1767d/dict_patterns-0.2.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-30 17:46:46",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "fferegrino",
    "github_project": "dict-patterns",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "dict-patterns"
}
        
Elapsed time: 0.96205s