Skip to main content

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!

Metadata

Release files for specipy 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for specipy 0.1.2
File Size Uploaded Provenance
specipy-0.1.2.tar.gz 4.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for specipy 0.1.2
File Interpreter ABI Platform
specipy-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 10.5 kB

Release files / specipy-0.1.2.tar.gz

Download URL specipy-0.1.2.tar.gz
Size 4.9 kB
Tags Source
SHA-256 checksum
How to use checksums
2a0c2168b4374d61a116543668be2e52dd692ec2650f64de562a69e779edc3e8
BLAKE2b-256 checksum
How to use checksums
4f2afa0af8f9ca41bf4604c0c94b73759b11aec9c22582134a9706309fd2bb95
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.9

Release files / specipy-0.1.2-py3-none-any.whl

Download URL specipy-0.1.2-py3-none-any.whl
Size 5.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
30ff3592d851cea5005f7516f24b35c16b9d7f54e83b5cc23948bf5f5a33703a
BLAKE2b-256 checksum
How to use checksums
f3494ea5f52b9b966aef60f0e78f906814475d5378829f60fa3e3277fb595f97
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.9

Security for specipy 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page