Skip to main content

No project description provided

Project description

SpeciPy

SpeciPy simplifies the implementation of the Specification pattern in Python, enabling easy creation and evaluation of flexible rules and criteria.

Build status Python Versions Package Version Coverage Status Code Style: Black License


📋 Table of Contents


📥 Installation

To install Interpy with pip, you can use the following command:

pip install specipy

If you are using poetry you can use the command:

poetry add specipy

🚀 Usage

SpeciPy provides a clean and powerful implementation of the Specification Pattern in Python. It helps you encapsulate business rules or filtering logic in a reusable and composable way.

Below are practical examples of how to use specipy in real-world scenarios:

Defining and using a simple specification

from specipy import Specification

class IsEven(Specification):
    def is_satisfied_by(self, candidate: int) -> bool:
        return candidate % 2 == 0

spec = IsEven()
print(spec.is_satisfied_by(4))  # True
print(spec.is_satisfied_by(7))  # False

Combining specifications with boolean logic

from specipy import Specification

class IsEven(Specification):
    def is_satisfied_by(self, candidate):
        return candidate % 2 == 0

class IsPositive(Specification):
    def is_satisfied_by(self, candidate):
        return candidate > 0

spec = IsEven() & IsPositive()

print(spec.is_satisfied_by(4))   # True (even and positive)
print(spec.is_satisfied_by(-2))  # False (even but negative)
print(spec.is_satisfied_by(3))   # False (odd)

You can also use | for OR and ~ for NOT:

spec = IsEven() | IsPositive()
print(spec.is_satisfied_by(-3))  # False
print(spec.is_satisfied_by(3))   # True

Filtering collections with specifications

from specipy import filter_by_spec, Specification

class StartsWithA(Specification):
    def is_satisfied_by(self, candidate):
        return candidate.lower().startswith("a")

names = ["Alice", "Bob", "anna", "Charles"]
spec = StartsWithA()

filtered = filter_by_spec(names, spec)
print(list(filtered))  # ['Alice', 'anna']

Validating complex domain rules

class HasBalance(Specification):
    def is_satisfied_by(self, account):
        return account.balance > 0

class IsActive(Specification):
    def is_satisfied_by(self, account):
        return account.active

class Account:
    def __init__(self, balance, active):
        self.balance = balance
        self.active = active

account = Account(balance=100, active=True)
spec = HasBalance() & IsActive()

print(spec.is_satisfied_by(account))  # True

This allows rules to be isolated, tested independently, and composed into more complex conditions.

Dynamic one-off specifications with lambdas

from specipy import lambda_spec

is_even = lambda_spec(lambda x: x % 2 == 0)

print(is_even.is_satisfied_by(10))  # True

Perfect for quick filters or dynamic rule creation without declaring classes.


📈 Roadmap / Future Goals

We plan to continue growing specipy into a robust, developer-friendly tool for business rule modeling. Some ideas we plan to explore:

✅ Planned Features

  • __str__ / __repr__ for debugging Clearer and descriptive output when printing specifications, like:

    print(GreaterThanSpecification(10))
    # Output: GreaterThanSpecification(10)
    
  • all_satisfied(specs) / any_satisfied(specs) Allows you to combine multiple specifications from a list dynamically:

    specs = [
        lambda_spec(lambda x: x > 10),
        lambda_spec(lambda x: x % 2 == 0),
    ]
    
    assert all_satisfied(specs)(12)  # True
    assert any_satisfied(specs)(9)   # False
    
  • spec.as_predicate() method Converts a specification into a simple callable predicate (function returning bool), making it easy to integrate with native Python functions like filter(), map(), or any functional programming context.

    spec = GreaterThanSpecification(5)
    list(filter(spec.as_predicate(), [1, 6, 8]))  # [6, 8]
    

🤝 Contributing

Specipy is designed to grow with the community. If you have ideas for new features, improvements, or bug fixes, we warmly welcome your contributions! Feel free to open issues, discuss enhancements, or submit pull requests. Together, we can make this library even more powerful and developer-friendly.

If you would like to contribute to Specipy, please follow these steps:

  1. Fork the repository git clone git@github.com:danieljoris/specipy.git
  2. Create a branch for your feature git checkout -b feature/your-feature
  3. Commit your changes git commit -m 'Add your feature
  4. Push to the branch git push origin feature/your-feature
  5. Open a Pull Request

📜 License

This project is licensed under the MIT License. See the LICENSE file for more details.


📧 Contact

Feel free to adjust and add more features as needed. If you need anything more specific or additional adjustments, let me know!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

specipy-0.1.2.tar.gz (4.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

specipy-0.1.2-py3-none-any.whl (5.6 kB view details)

Uploaded Python 3

File details

Details for the file specipy-0.1.2.tar.gz.

File metadata

  • Download URL: specipy-0.1.2.tar.gz
  • Upload date:
  • Size: 4.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for specipy-0.1.2.tar.gz
Algorithm Hash digest
SHA256 2a0c2168b4374d61a116543668be2e52dd692ec2650f64de562a69e779edc3e8
MD5 e69bcfd80f50843d9952194f1376f136
BLAKE2b-256 4f2afa0af8f9ca41bf4604c0c94b73759b11aec9c22582134a9706309fd2bb95

See more details on using hashes here.

File details

Details for the file specipy-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: specipy-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 5.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for specipy-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 30ff3592d851cea5005f7516f24b35c16b9d7f54e83b5cc23948bf5f5a33703a
MD5 aa66ef35a0dfdf13233edf56ea830dc4
BLAKE2b-256 f3494ea5f52b9b966aef60f0e78f906814475d5378829f60fa3e3277fb595f97

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page