# 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"
}