# py-collections
A Python collections library providing enhanced collection types with additional functionality, built using a modular mixin architecture.
## Development Setup
This project uses [uv](https://github.com/astral-sh/uv) for dependency management and Python environment management.
### Prerequisites
- Python 3.13+
- [uv](https://github.com/astral-sh/uv) installed
- [taskipy](https://github.com/taskipy/taskipy) (optional, for easier command execution)
### Installation
1. Clone the repository
2. Install dependencies:
```bash
uv sync
```
3. Install the package in development mode (for running examples):
```bash
uv pip install -e .
```
4. (Optional) Install taskipy globally for easier command execution:
```bash
pip install taskipy
```
### Running Tests
To run all tests:
```bash
uv run pytest
```
To run tests with verbose output:
```bash
uv run pytest -v
```
To run tests with coverage:
```bash
uv run pytest --cov=src/py_collections --cov-report=term-missing
```
To generate HTML coverage report:
```bash
uv run pytest --cov=src/py_collections --cov-report=html --cov-report=term-missing
```
To run a specific test file:
```bash
uv run pytest tests/core/test_init.py
```
To run tests for a specific mixin:
```bash
uv run pytest tests/mixins/basic_operations/
uv run pytest tests/mixins/transformation/
```
To run tests in watch mode (re-runs on file changes):
```bash
uv run pytest --watch
```
### Development Commands
#### Using taskipy (recommended)
If you have taskipy installed globally (`pip install taskipy`):
- **Install dev dependencies**: `uv sync --group dev`
- **Run linting**: `task check`
- **Format code**: `task format`
- **Check formatting**: `task format-check`
- **Auto-fix linting issues**: `task check-fix`
- **Run tests**: `task test`
- **Run tests with verbose output**: `task test-verbose`
- **Run tests with coverage**: `task test-coverage`
- **Run tests with HTML coverage report**: `task test-coverage-html`
- **Run all checks**: `task lint`
- **Run linting, formatting, and tests**: `task all`
If you don't have taskipy installed globally, use:
- **Run linting**: `uv run python -c "from taskipy import cli; cli.main()" check`
- **Format code**: `uv run python -c "from taskipy import cli; cli.main()" format`
- **Check formatting**: `uv run python -c "from taskipy import cli; cli.main()" format-check`
- **Auto-fix linting issues**: `uv run python -c "from taskipy import cli; cli.main()" check-fix`
- **Run tests**: `uv run python -c "from taskipy import cli; cli.main()" test`
- **Run tests with verbose output**: `uv run python -c "from taskipy import cli; cli.main()" test-verbose`
- **Run tests with coverage**: `uv run python -c "from taskipy import cli; cli.main()" test-coverage`
- **Run tests with HTML coverage report**: `uv run python -c "from taskipy import cli; cli.main()" test-coverage-html`
- **Run all checks**: `uv run python -c "from taskipy import cli; cli.main()" lint`
- **Run linting, formatting, and tests**: `uv run python -c "from taskipy import cli; cli.main()" all`
#### Using uv directly
- **Run linting**: `uv run ruff check .`
- **Format code**: `uv run ruff format .`
- **Type checking**: `uv run mypy src/`
- **Run all checks**: `uv run ruff check . && uv run ruff format --check .`
## Project Structure
```
py-collections/
├── src/py_collections/ # Main package source code
│ ├── collection.py # Main Collection class (combines all mixins)
│ ├── collection_map.py # CollectionMap class
│ └── mixins/ # Modular mixin classes
│ ├── basic_operations.py # append, extend, all, len, iteration
│ ├── element_access.py # first, last, exists, first_or_raise
│ ├── navigation.py # after, before
│ ├── transformation.py # map, pluck, filter, reverse, clone
│ ├── grouping.py # group_by, chunk
│ ├── removal.py # remove, remove_one
│ └── utility.py # take, dump_me, dump_me_and_die
├── tests/ # Test files organized by functionality
│ ├── core/ # Core Collection tests
│ ├── collection_map/ # CollectionMap tests
│ └── mixins/ # Tests organized by mixin
│ ├── basic_operations/
│ ├── element_access/
│ ├── navigation/
│ ├── transformation/
│ ├── grouping/
│ ├── removal/
│ └── utility/
├── examples/ # Example usage and demonstrations
├── pyproject.toml # Project configuration and dependencies
└── README.md # This file
```
## Architecture
The library uses a **mixin-based architecture** to provide modular, maintainable code:
### Mixin Classes
Each mixin provides a focused set of related functionality:
- **BasicOperationsMixin**: Core collection operations (append, extend, all, len, iteration)
- **ElementAccessMixin**: Element retrieval and existence checking (first, last, exists, first_or_raise)
- **NavigationMixin**: Relative element access (after, before)
- **TransformationMixin**: Data transformation operations (map, pluck, filter, reverse, clone)
- **GroupingMixin**: Data grouping and chunking (group_by, chunk)
- **RemovalMixin**: Element removal operations (remove, remove_one)
- **UtilityMixin**: Utility and debugging methods (take, dump_me, dump_me_and_die)
### Benefits of This Architecture
1. **Modularity**: Each mixin focuses on a specific domain of functionality
2. **Maintainability**: Changes to one area don't affect others
3. **Testability**: Tests are organized by functionality
4. **Extensibility**: New functionality can be added as new mixins
5. **Reusability**: Mixins can be used independently if needed
## Features
- Enhanced collection types with additional utility methods
- **Modular mixin architecture** for maintainable code
- Type-safe implementations with full generic support
- **100% test coverage** - All code paths tested
- Modern Python features (3.13+)
- Specialized `CollectionMap` for working with grouped data
- Code quality tools: Ruff (linting + formatting), MyPy (type checking)
## Available Methods
The `Collection` class provides the following methods, organized by mixin:
### Basic Operations (BasicOperationsMixin)
- `append(item)` - Add an item to the collection
- `extend(items)` - Add multiple items from a list or another collection
- `all()` - Get all items as a list
- `len()` - Get the number of items
- **Iteration** - Use in `for` loops and with built-in functions like `sum()`, `max()`, `min()`, `any()`, `all()`, etc.
### Element Access (ElementAccessMixin)
- `first(predicate=None)` - Get the first element (optionally matching a predicate)
- `first_or_raise(predicate=None)` - Get the first element or raise exception if not found
- `last()` - Get the last element
- `exists(predicate=None)` - Check if an element exists (returns boolean)
### Navigation (NavigationMixin)
- `after(target)` - Get the element after a target element or predicate match
- `before(target)` - Get the element before a target element or predicate match
### Transformation (TransformationMixin)
- `filter(predicate)` - Filter elements based on a predicate
- `map(func)` - Apply a function to every item and return a new collection with the results
- `pluck(key, value_key=None)` - Extract values from items based on a key or attribute (inspired by Laravel)
- `reverse()` - Return a new collection with items in reverse order
- `clone()` - Return a new collection with the same items
### Grouping (GroupingMixin)
- `group_by(key)` - Group items by a key or callback function
- `chunk(size)` - Split collection into smaller chunks
### Removal (RemovalMixin)
- `remove(target)` - Remove all items that match the target element or predicate (modifies collection in-place)
- `remove_one(target)` - Remove the first occurrence of an item that matches the target element or predicate (modifies collection in-place)
### Utility (UtilityMixin)
- `take(count)` - Return a new collection with the specified number of items (positive: from beginning, negative: from end)
- `dump_me()` - Debug method to print collection contents (doesn't stop execution)
- `dump_me_and_die()` - Debug method to print collection contents and stop execution
- `to_dict(mode=None)` - Convert items to plain Python structures. With `mode="json"`, ensures JSON-serializable output (datetimes to ISO strings, Decimals to floats, UUIDs to strings, sets to lists, and dict keys to strings)
- `to_json()` - Return a JSON string using `to_dict(mode="json")`
### CollectionMap Class
A specialized map that stores `Collection` instances as values, providing convenient methods for working with grouped data:
- Dictionary-like interface with string keys and Collection values
- Automatic conversion of lists/items to Collection instances
- `get(key)` - Returns empty Collection if key doesn't exist (no KeyError)
- `add(key, items)` - Add items to existing key or create new key
- `flatten()` - Combine all collections into one
- `map(func)` - Apply function to each collection
- `filter(predicate)` - Filter collections based on criteria
- `filter_by_size(min_size, max_size)` - Filter by collection size
- `total_items()` - Get total count across all collections
- `largest_group()` / `smallest_group()` - Find groups by size
- `group_sizes()` - Get size of each group
### Usage Examples
```python
from py_collections import Collection
# Basic usage
numbers = Collection([1, 2, 3, 4, 5])
numbers.append(6)
# Extending with multiple items
numbers.extend([7, 8, 9])
other_numbers = Collection([10, 11, 12])
numbers.extend(other_numbers)
# Reversing the collection
reversed_numbers = numbers.reverse()
# Cloning the collection
cloned_numbers = numbers.clone() # Create a copy with the same items
# Taking items from the collection
first_two = numbers.take(2) # Take first 2 items
last_three = numbers.take(-3) # Take last 3 items
# Mapping elements
doubled = numbers.map(lambda x: x * 2) # Double each number
squared = numbers.map(lambda x: x ** 2) # Square each number
strings = numbers.map(str) # Convert to strings
# Plucking values from objects/dictionaries
users = Collection([{"name": "Alice", "age": 25}, {"name": "Bob", "age": 30}])
names = users.pluck("name") # ["Alice", "Bob"]
name_age_pairs = users.pluck("name", "age") # [{"Alice": 25}, {"Bob": 30}]
# Nested key access with dot notation
nested_users = Collection([{"name": "Alice", "address": {"city": "NYC"}}, {"name": "Bob", "address": {"city": "LA"}}])
cities = nested_users.pluck("address.city") # ["NYC", "LA"]
name_city_pairs = nested_users.pluck("name", "address.city") # [{"Alice": "NYC"}, {"Bob": "LA"}]
# Removing elements
numbers.remove(1) # Remove all occurrences of 1
numbers.remove(lambda x: x > 3) # Remove all elements > 3
numbers.remove_one(lambda x: x == 2) # Remove first occurrence of 2
# Check if elements exist
if numbers.exists(lambda x: x > 3):
print("Found number greater than 3")
# Find elements
first_even = numbers.first(lambda x: x % 2 == 0)
after_three = numbers.after(3)
# Filter and chunk
evens = numbers.filter(lambda x: x % 2 == 0)
chunks = numbers.chunk(2)
# Group by
users = Collection([{"name": "Alice", "dept": "Eng"}, {"name": "Bob", "dept": "Sales"}])
by_dept = users.group_by("dept")
by_parity = numbers.group_by(lambda x: "even" if x % 2 == 0 else "odd")
# Iteration
for item in numbers:
print(item)
# List comprehension
doubled = [item * 2 for item in numbers]
# Built-in functions
total = sum(item for item in numbers)
has_even = any(item % 2 == 0 for item in numbers)
# CollectionMap usage
# Serialization
from py_collections import Collection
data = Collection([
{"name": "Alice", "age": 30},
(1, 2, 3),
{"tags": {"python", "collections"}},
])
# Plain Python structures
structure = data.to_dict()
# JSON-ready structure and JSON string
json_ready = data.to_dict(mode="json")
json_text = data.to_json()
### Pydantic Compatibility
If your items include Pydantic models, they are supported out of the box:
```python
from pydantic import BaseModel
from py_collections import Collection
class User(BaseModel):
id: int
name: str
users = Collection([User(id=1, name="Alice"), User(id=2, name="Bob")])
# Converts to list of dicts
users_dict = users.to_dict()
# JSON-ready and stringified
users_json_ready = users.to_dict(mode="json")
users_json = users.to_json()
```
from py_collections import CollectionMap
# Create from group_by result
grouped = users.group_by("department")
cmap = CollectionMap(grouped)
# Work with groups
engineering = cmap["Engineering"]
all_users = cmap.flatten()
group_stats = cmap.map(lambda c: len(c))
# Safe access and incremental building
missing = cmap.get("missing") # Returns empty Collection
cmap.add("new_group", [1, 2, 3]) # Creates new group
cmap.add("existing_group", [4, 5]) # Extends existing group
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for new functionality
5. Run tests: `uv run pytest`
6. Submit a pull request
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
Raw data
{
"_id": null,
"home_page": null,
"name": "py-collections",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.13",
"maintainer_email": "Matias Gallardo <10453322+mato777@users.noreply.github.com>",
"keywords": "collections, data-structures, dict, functional-programming, json, list, mixin, python, serialization, utility",
"author": null,
"author_email": "Matias Gallardo <10453322+mato777@users.noreply.github.com>",
"download_url": "https://files.pythonhosted.org/packages/27/76/9eaf73ad44f71eae55a8dadd8e401467721ba2e8e33252eec96cfcbf8033/py_collections-0.1.3.tar.gz",
"platform": null,
"description": "# py-collections\n\nA Python collections library providing enhanced collection types with additional functionality, built using a modular mixin architecture.\n\n## Development Setup\n\nThis project uses [uv](https://github.com/astral-sh/uv) for dependency management and Python environment management.\n\n### Prerequisites\n\n- Python 3.13+\n- [uv](https://github.com/astral-sh/uv) installed\n- [taskipy](https://github.com/taskipy/taskipy) (optional, for easier command execution)\n\n### Installation\n\n1. Clone the repository\n2. Install dependencies:\n ```bash\n uv sync\n ```\n3. Install the package in development mode (for running examples):\n ```bash\n uv pip install -e .\n ```\n\n4. (Optional) Install taskipy globally for easier command execution:\n ```bash\n pip install taskipy\n ```\n\n### Running Tests\n\nTo run all tests:\n```bash\nuv run pytest\n```\n\nTo run tests with verbose output:\n```bash\nuv run pytest -v\n```\n\nTo run tests with coverage:\n```bash\nuv run pytest --cov=src/py_collections --cov-report=term-missing\n```\n\nTo generate HTML coverage report:\n```bash\nuv run pytest --cov=src/py_collections --cov-report=html --cov-report=term-missing\n```\n\nTo run a specific test file:\n```bash\nuv run pytest tests/core/test_init.py\n```\n\nTo run tests for a specific mixin:\n```bash\nuv run pytest tests/mixins/basic_operations/\nuv run pytest tests/mixins/transformation/\n```\n\nTo run tests in watch mode (re-runs on file changes):\n```bash\nuv run pytest --watch\n```\n\n### Development Commands\n\n#### Using taskipy (recommended)\nIf you have taskipy installed globally (`pip install taskipy`):\n- **Install dev dependencies**: `uv sync --group dev`\n- **Run linting**: `task check`\n- **Format code**: `task format`\n- **Check formatting**: `task format-check`\n- **Auto-fix linting issues**: `task check-fix`\n- **Run tests**: `task test`\n- **Run tests with verbose output**: `task test-verbose`\n- **Run tests with coverage**: `task test-coverage`\n- **Run tests with HTML coverage report**: `task test-coverage-html`\n- **Run all checks**: `task lint`\n- **Run linting, formatting, and tests**: `task all`\n\nIf you don't have taskipy installed globally, use:\n- **Run linting**: `uv run python -c \"from taskipy import cli; cli.main()\" check`\n- **Format code**: `uv run python -c \"from taskipy import cli; cli.main()\" format`\n- **Check formatting**: `uv run python -c \"from taskipy import cli; cli.main()\" format-check`\n- **Auto-fix linting issues**: `uv run python -c \"from taskipy import cli; cli.main()\" check-fix`\n- **Run tests**: `uv run python -c \"from taskipy import cli; cli.main()\" test`\n- **Run tests with verbose output**: `uv run python -c \"from taskipy import cli; cli.main()\" test-verbose`\n- **Run tests with coverage**: `uv run python -c \"from taskipy import cli; cli.main()\" test-coverage`\n- **Run tests with HTML coverage report**: `uv run python -c \"from taskipy import cli; cli.main()\" test-coverage-html`\n- **Run all checks**: `uv run python -c \"from taskipy import cli; cli.main()\" lint`\n- **Run linting, formatting, and tests**: `uv run python -c \"from taskipy import cli; cli.main()\" all`\n\n#### Using uv directly\n- **Run linting**: `uv run ruff check .`\n- **Format code**: `uv run ruff format .`\n- **Type checking**: `uv run mypy src/`\n- **Run all checks**: `uv run ruff check . && uv run ruff format --check .`\n\n## Project Structure\n\n```\npy-collections/\n\u251c\u2500\u2500 src/py_collections/ # Main package source code\n\u2502 \u251c\u2500\u2500 collection.py # Main Collection class (combines all mixins)\n\u2502 \u251c\u2500\u2500 collection_map.py # CollectionMap class\n\u2502 \u2514\u2500\u2500 mixins/ # Modular mixin classes\n\u2502 \u251c\u2500\u2500 basic_operations.py # append, extend, all, len, iteration\n\u2502 \u251c\u2500\u2500 element_access.py # first, last, exists, first_or_raise\n\u2502 \u251c\u2500\u2500 navigation.py # after, before\n\u2502 \u251c\u2500\u2500 transformation.py # map, pluck, filter, reverse, clone\n\u2502 \u251c\u2500\u2500 grouping.py # group_by, chunk\n\u2502 \u251c\u2500\u2500 removal.py # remove, remove_one\n\u2502 \u2514\u2500\u2500 utility.py # take, dump_me, dump_me_and_die\n\u251c\u2500\u2500 tests/ # Test files organized by functionality\n\u2502 \u251c\u2500\u2500 core/ # Core Collection tests\n\u2502 \u251c\u2500\u2500 collection_map/ # CollectionMap tests\n\u2502 \u2514\u2500\u2500 mixins/ # Tests organized by mixin\n\u2502 \u251c\u2500\u2500 basic_operations/\n\u2502 \u251c\u2500\u2500 element_access/\n\u2502 \u251c\u2500\u2500 navigation/\n\u2502 \u251c\u2500\u2500 transformation/\n\u2502 \u251c\u2500\u2500 grouping/\n\u2502 \u251c\u2500\u2500 removal/\n\u2502 \u2514\u2500\u2500 utility/\n\u251c\u2500\u2500 examples/ # Example usage and demonstrations\n\u251c\u2500\u2500 pyproject.toml # Project configuration and dependencies\n\u2514\u2500\u2500 README.md # This file\n```\n\n## Architecture\n\nThe library uses a **mixin-based architecture** to provide modular, maintainable code:\n\n### Mixin Classes\n\nEach mixin provides a focused set of related functionality:\n\n- **BasicOperationsMixin**: Core collection operations (append, extend, all, len, iteration)\n- **ElementAccessMixin**: Element retrieval and existence checking (first, last, exists, first_or_raise)\n- **NavigationMixin**: Relative element access (after, before)\n- **TransformationMixin**: Data transformation operations (map, pluck, filter, reverse, clone)\n- **GroupingMixin**: Data grouping and chunking (group_by, chunk)\n- **RemovalMixin**: Element removal operations (remove, remove_one)\n- **UtilityMixin**: Utility and debugging methods (take, dump_me, dump_me_and_die)\n\n### Benefits of This Architecture\n\n1. **Modularity**: Each mixin focuses on a specific domain of functionality\n2. **Maintainability**: Changes to one area don't affect others\n3. **Testability**: Tests are organized by functionality\n4. **Extensibility**: New functionality can be added as new mixins\n5. **Reusability**: Mixins can be used independently if needed\n\n## Features\n\n- Enhanced collection types with additional utility methods\n- **Modular mixin architecture** for maintainable code\n- Type-safe implementations with full generic support\n- **100% test coverage** - All code paths tested\n- Modern Python features (3.13+)\n- Specialized `CollectionMap` for working with grouped data\n- Code quality tools: Ruff (linting + formatting), MyPy (type checking)\n\n## Available Methods\n\nThe `Collection` class provides the following methods, organized by mixin:\n\n### Basic Operations (BasicOperationsMixin)\n- `append(item)` - Add an item to the collection\n- `extend(items)` - Add multiple items from a list or another collection\n- `all()` - Get all items as a list\n- `len()` - Get the number of items\n- **Iteration** - Use in `for` loops and with built-in functions like `sum()`, `max()`, `min()`, `any()`, `all()`, etc.\n\n### Element Access (ElementAccessMixin)\n- `first(predicate=None)` - Get the first element (optionally matching a predicate)\n- `first_or_raise(predicate=None)` - Get the first element or raise exception if not found\n- `last()` - Get the last element\n- `exists(predicate=None)` - Check if an element exists (returns boolean)\n\n### Navigation (NavigationMixin)\n- `after(target)` - Get the element after a target element or predicate match\n- `before(target)` - Get the element before a target element or predicate match\n\n### Transformation (TransformationMixin)\n- `filter(predicate)` - Filter elements based on a predicate\n- `map(func)` - Apply a function to every item and return a new collection with the results\n- `pluck(key, value_key=None)` - Extract values from items based on a key or attribute (inspired by Laravel)\n- `reverse()` - Return a new collection with items in reverse order\n- `clone()` - Return a new collection with the same items\n\n### Grouping (GroupingMixin)\n- `group_by(key)` - Group items by a key or callback function\n- `chunk(size)` - Split collection into smaller chunks\n\n### Removal (RemovalMixin)\n- `remove(target)` - Remove all items that match the target element or predicate (modifies collection in-place)\n- `remove_one(target)` - Remove the first occurrence of an item that matches the target element or predicate (modifies collection in-place)\n\n### Utility (UtilityMixin)\n- `take(count)` - Return a new collection with the specified number of items (positive: from beginning, negative: from end)\n- `dump_me()` - Debug method to print collection contents (doesn't stop execution)\n- `dump_me_and_die()` - Debug method to print collection contents and stop execution\n- `to_dict(mode=None)` - Convert items to plain Python structures. With `mode=\"json\"`, ensures JSON-serializable output (datetimes to ISO strings, Decimals to floats, UUIDs to strings, sets to lists, and dict keys to strings)\n- `to_json()` - Return a JSON string using `to_dict(mode=\"json\")`\n\n### CollectionMap Class\nA specialized map that stores `Collection` instances as values, providing convenient methods for working with grouped data:\n- Dictionary-like interface with string keys and Collection values\n- Automatic conversion of lists/items to Collection instances\n- `get(key)` - Returns empty Collection if key doesn't exist (no KeyError)\n- `add(key, items)` - Add items to existing key or create new key\n- `flatten()` - Combine all collections into one\n- `map(func)` - Apply function to each collection\n- `filter(predicate)` - Filter collections based on criteria\n- `filter_by_size(min_size, max_size)` - Filter by collection size\n- `total_items()` - Get total count across all collections\n- `largest_group()` / `smallest_group()` - Find groups by size\n- `group_sizes()` - Get size of each group\n\n### Usage Examples\n\n```python\nfrom py_collections import Collection\n\n# Basic usage\nnumbers = Collection([1, 2, 3, 4, 5])\nnumbers.append(6)\n\n# Extending with multiple items\nnumbers.extend([7, 8, 9])\nother_numbers = Collection([10, 11, 12])\nnumbers.extend(other_numbers)\n\n# Reversing the collection\nreversed_numbers = numbers.reverse()\n\n# Cloning the collection\ncloned_numbers = numbers.clone() # Create a copy with the same items\n\n# Taking items from the collection\nfirst_two = numbers.take(2) # Take first 2 items\nlast_three = numbers.take(-3) # Take last 3 items\n\n# Mapping elements\ndoubled = numbers.map(lambda x: x * 2) # Double each number\nsquared = numbers.map(lambda x: x ** 2) # Square each number\nstrings = numbers.map(str) # Convert to strings\n\n# Plucking values from objects/dictionaries\nusers = Collection([{\"name\": \"Alice\", \"age\": 25}, {\"name\": \"Bob\", \"age\": 30}])\nnames = users.pluck(\"name\") # [\"Alice\", \"Bob\"]\nname_age_pairs = users.pluck(\"name\", \"age\") # [{\"Alice\": 25}, {\"Bob\": 30}]\n\n# Nested key access with dot notation\nnested_users = Collection([{\"name\": \"Alice\", \"address\": {\"city\": \"NYC\"}}, {\"name\": \"Bob\", \"address\": {\"city\": \"LA\"}}])\ncities = nested_users.pluck(\"address.city\") # [\"NYC\", \"LA\"]\nname_city_pairs = nested_users.pluck(\"name\", \"address.city\") # [{\"Alice\": \"NYC\"}, {\"Bob\": \"LA\"}]\n\n# Removing elements\nnumbers.remove(1) # Remove all occurrences of 1\nnumbers.remove(lambda x: x > 3) # Remove all elements > 3\nnumbers.remove_one(lambda x: x == 2) # Remove first occurrence of 2\n\n# Check if elements exist\nif numbers.exists(lambda x: x > 3):\n print(\"Found number greater than 3\")\n\n# Find elements\nfirst_even = numbers.first(lambda x: x % 2 == 0)\nafter_three = numbers.after(3)\n\n# Filter and chunk\nevens = numbers.filter(lambda x: x % 2 == 0)\nchunks = numbers.chunk(2)\n\n# Group by\nusers = Collection([{\"name\": \"Alice\", \"dept\": \"Eng\"}, {\"name\": \"Bob\", \"dept\": \"Sales\"}])\nby_dept = users.group_by(\"dept\")\nby_parity = numbers.group_by(lambda x: \"even\" if x % 2 == 0 else \"odd\")\n\n# Iteration\nfor item in numbers:\n print(item)\n\n# List comprehension\ndoubled = [item * 2 for item in numbers]\n\n# Built-in functions\ntotal = sum(item for item in numbers)\nhas_even = any(item % 2 == 0 for item in numbers)\n\n# CollectionMap usage\n# Serialization\nfrom py_collections import Collection\n\ndata = Collection([\n {\"name\": \"Alice\", \"age\": 30},\n (1, 2, 3),\n {\"tags\": {\"python\", \"collections\"}},\n])\n\n# Plain Python structures\nstructure = data.to_dict()\n\n# JSON-ready structure and JSON string\njson_ready = data.to_dict(mode=\"json\")\njson_text = data.to_json()\n\n### Pydantic Compatibility\nIf your items include Pydantic models, they are supported out of the box:\n\n```python\nfrom pydantic import BaseModel\nfrom py_collections import Collection\n\nclass User(BaseModel):\n id: int\n name: str\n\nusers = Collection([User(id=1, name=\"Alice\"), User(id=2, name=\"Bob\")])\n\n# Converts to list of dicts\nusers_dict = users.to_dict()\n\n# JSON-ready and stringified\nusers_json_ready = users.to_dict(mode=\"json\")\nusers_json = users.to_json()\n```\n\nfrom py_collections import CollectionMap\n\n# Create from group_by result\ngrouped = users.group_by(\"department\")\ncmap = CollectionMap(grouped)\n\n# Work with groups\nengineering = cmap[\"Engineering\"]\nall_users = cmap.flatten()\ngroup_stats = cmap.map(lambda c: len(c))\n\n# Safe access and incremental building\nmissing = cmap.get(\"missing\") # Returns empty Collection\ncmap.add(\"new_group\", [1, 2, 3]) # Creates new group\ncmap.add(\"existing_group\", [4, 5]) # Extends existing group\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Add tests for new functionality\n5. Run tests: `uv run pytest`\n6. Submit a pull request\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A Python collections library providing enhanced collection types with additional functionality",
"version": "0.1.3",
"project_urls": {
"Bug Tracker": "https://github.com/mato777/py-collections/issues",
"Documentation": "https://github.com/mato777/py-collections#readme",
"Homepage": "https://github.com/mato777/py-collections",
"Repository": "https://github.com/mato777/py-collections",
"Source Code": "https://github.com/mato777/py-collections"
},
"split_keywords": [
"collections",
" data-structures",
" dict",
" functional-programming",
" json",
" list",
" mixin",
" python",
" serialization",
" utility"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "d2bccc566ce5e320cfa101d2aaeb5a1b9358badc27a3ca31d0c87e3cb0a60166",
"md5": "8e58c01fedacdb78709ac0da6f01b805",
"sha256": "b9469a8a412919ee65de844be30ea7053e9984c366b75b2bfa4cc34eefdd9d1a"
},
"downloads": -1,
"filename": "py_collections-0.1.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "8e58c01fedacdb78709ac0da6f01b805",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.13",
"size": 19790,
"upload_time": "2025-09-07T06:27:00",
"upload_time_iso_8601": "2025-09-07T06:27:00.245795Z",
"url": "https://files.pythonhosted.org/packages/d2/bc/cc566ce5e320cfa101d2aaeb5a1b9358badc27a3ca31d0c87e3cb0a60166/py_collections-0.1.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "27769eaf73ad44f71eae55a8dadd8e401467721ba2e8e33252eec96cfcbf8033",
"md5": "60756df8776819f2637c7a36d51a2323",
"sha256": "5e3a84dde4eb1b19d509d73ffd9d1fea3445b1191be2f4f6f124e8ca2aa7e842"
},
"downloads": -1,
"filename": "py_collections-0.1.3.tar.gz",
"has_sig": false,
"md5_digest": "60756df8776819f2637c7a36d51a2323",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.13",
"size": 79420,
"upload_time": "2025-09-07T06:27:01",
"upload_time_iso_8601": "2025-09-07T06:27:01.244308Z",
"url": "https://files.pythonhosted.org/packages/27/76/9eaf73ad44f71eae55a8dadd8e401467721ba2e8e33252eec96cfcbf8033/py_collections-0.1.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-07 06:27:01",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "mato777",
"github_project": "py-collections",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "py-collections"
}