Skip to main content

A generic filtering framework using abstract composition

Project description

🔍 pfylter PyPI GitHub

pfylter is a lightweight, flexible, and extensible Python framework for applying composable filters to arbitrary data. It’s built using the composite design pattern, allowing complex logical conditions to be expressed and reused cleanly.


📑 Table of Contents


🚀 Features

  • ✅ Define your own filters by subclassing AbstractFilter
  • ✅ Combine filters using logical AND (AllFilters) or OR (AnyFilter)
  • ✅ Support for generic data types (strings, numbers, objects, etc.)
  • ✅ Clean, readable syntax using list comprehensions and type hints
  • ✅ Perfect for data processing, rule engines, and validation pipelines

📦 Installation

pip install pfylter

✨ Quick Start

These simple examples with number uses the LambdaFilter class to build filters based on lambda functions.

Let's start with a simple filter to get numbers greater than 5 or it's oposite condition using NotFilter.

from pfylter.core import LambdaFilter, NotFilter, AllFilters, AnyFilter

example = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

print('Numbers greater than 5:')
print(LambdaFilter(lambda x: x > 5).apply(example))  # [6, 7, 8, 9, 10]

print('Numbers equal or lower than 5:')
print(NotFilter(LambdaFilter(lambda x: x > 5)).apply(example))  # [1, 2, 3, 4, 5]

Now, use AllFilters and AnyFilter to create filters by aggregating other filters. When AllFilters is used, only elements that meet all filters in the list are kept.

print('Numbers greater than 5 and divisible by two:')
print(AllFilters([
    LambdaFilter(lambda x: x > 5),
    LambdaFilter(lambda x: x % 2 == 0)
]).apply(example))  # [6, 8, 10]

print('Numbers greater than 5 and divisible by three:')
print(AllFilters([
    LambdaFilter(lambda x: x > 5),
    LambdaFilter(lambda x: x % 3 == 0)
]).apply(example))  # [6, 9]

When AnyFilter, elements that meet any of the filters in the list are kept (i.e. meet any of the filters is enough to be in the output).

print('Numbers greater than 5 or divisible by two:')
print(AnyFilter([
    LambdaFilter(lambda x: x > 5),
    LambdaFilter(lambda x: x % 2 == 0)
]).apply(example))  # [2, 4, 6, 7, 8, 9, 10]

🧩 Predefined String Filters

The pfylter.strings module provides ready-to-use filters for common string operations:

  • LenFilter(length): keeps strings of a given length.
  • LengthRangeFilter(min, max): keeps strings of length within the specified range.
  • EndsWithFilter(prefix): keeps strings that start with a prefix.
  • StartsWithFilter(prefix): keeps strings that end with a prefix.
  • ContainsFilter(substring): keeps strings that contain a substring.
  • RegexFilter(substring): keeps strings that match the specified regular expression.

Starting with a list of strings, here we have some uses of these basic filters.

from pfylter.strings import LenFilter, StartsWithFilter, ContainsFilter, NotFilter
from pfylter.core import AllFilters, AnyFilter

example = ['A', 'ABCD', 'B', 'BCDE', 'C', 'AAAAAAA']

print('Strings containing "BC":')
print(ContainsFilter('BC').apply(example))

print('Strings with length one:')
print(LenFilter(1).apply(example))

print('Strings with length different than one:')
print(NotFilter(LenFilter(1)).apply(example))

print('Strings with length four and starting with "A":')
print(AllFilters([LenFilter(4), StartsWithFilter('A')]).apply(example))  

print('Strings with length four or starting with "A":')
print(AnyFilter([LenFilter(4), StartsWithFilter('A')]).apply(example))

More complex filters can be created creating an AnyFilter with two AllFilters objects to output all strings that either have length four and start with "A" or have length one and start with "B".

print('Strings with length four and starting with "A" or length one and starting with "B":')
print(AnyFilter([
    AllFilters([LenFilter(4), StartsWithFilter('A')]),
    AllFilters([LenFilter(1), StartsWithFilter('B')])
]).apply(example))  # ['ABCD', 'B']

Finally, the NotFilter can be combined with AllFilters or AnyFilter to create exclusion filters. These two examples are equivalent and allow excluding strings that contain "BC" (this excludes "ABCD" and "BCDE") or have length 1 (this excludes "A", "B, and "C").

print('Exclude any string that includes BC or has length 1 (using AllFilters):')
print(AllFilters([NotFilter(LenFilter(1)), NotFilter(ContainsFilter('BC'))]).apply(example))  # ['AAAAAAA']

print('Exclude any string that includes BC or has length 1 (using AnyFilter):')
print(NotFilter(AnyFilter([ContainsFilter('BC'), LenFilter(1)])).apply(example))  # ['AAAAAAA']

🛠 Creating Custom Filters

You can define custom filters by inheriting from AbstractFilter:

from pfylter import AbstractFilter

class GreaterThanFilter(AbstractFilter[int]):
    def __init__(self, threshold: int):
        self.threshold = threshold

    def keep(self, instance: int) -> bool:
        return instance > self.threshold

Now you can use this filter in combination with others!


📝 License

MIT License — see LICENSE file for details.


🤝 Contributing

Feel free to open issues or pull requests. All feedback is welcome!

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

pfylter-0.3.0.tar.gz (5.5 kB view details)

Uploaded Source

Built Distribution

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

pfylter-0.3.0-py3-none-any.whl (5.6 kB view details)

Uploaded Python 3

File details

Details for the file pfylter-0.3.0.tar.gz.

File metadata

  • Download URL: pfylter-0.3.0.tar.gz
  • Upload date:
  • Size: 5.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.12

File hashes

Hashes for pfylter-0.3.0.tar.gz
Algorithm Hash digest
SHA256 da7f56c79ff439ff0b597d7025218f13bf7b49bdeffba9a972ba05655ef8e72c
MD5 90979039a037bfa1a9062a62267b9c92
BLAKE2b-256 7599b91c83b4e7b91636137109f25e50f18c1ce7992a1ffdece624f931e410b5

See more details on using hashes here.

File details

Details for the file pfylter-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: pfylter-0.3.0-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.11.12

File hashes

Hashes for pfylter-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0a0dfe2febc4a828cc83fa747aecdb8e5db8bb75da27204328779946833160d3
MD5 33fae313b0f4aea1372c95b5d249b774
BLAKE2b-256 c918015e8c2a11c5284c64c01c9872c4c8c495d0fb7b26dc3ac6c6d1f67fd735

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