Skip to main content

A generic filtering framework using abstract composition

Project description

🔍 pfylter

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.
  • StartsWithFilter(prefix): keeps strings that start with a prefix.
  • ContainsFilter(substring): keeps strings that contain a substring.

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.2.1.tar.gz (5.0 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.2.1-py3-none-any.whl (5.2 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for pfylter-0.2.1.tar.gz
Algorithm Hash digest
SHA256 f7e2af09eb58439c2bb5c6a4bd97083023844c95f878804b4c839e9d5e849ea9
MD5 9d550034c7b9f5887a685a73d90dedfa
BLAKE2b-256 bc0b2df8143f1251eff75cb0cff551c1c05af473ef3bd667fdd637ad3c9b2a5d

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pfylter-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 5.2 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.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 26be980efe13bdd8337986fe43aef491ef8c37e20e56bca6173981d5317eba8c
MD5 5925263e2689cf4b6fb1c37534973502
BLAKE2b-256 60ea018dbef1a7c5674575520e96c8e46a97fb9f2b509cb0a51995bc17bd3523

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