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.
  • 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.2.tar.gz (5.1 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.2-py3-none-any.whl (5.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pfylter-0.2.2.tar.gz
  • Upload date:
  • Size: 5.1 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.2.tar.gz
Algorithm Hash digest
SHA256 c49219bb79b9dd44099323c51e45fcf41464c6ef102d88a02ac893fc28fe8c8b
MD5 9679eda15f3ae957680040ae6e3fe242
BLAKE2b-256 2d25dac1d7279f367e5dfb90bbb424c65afbb02ff74e174e17e3426c13ff0cf7

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pfylter-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 5.3 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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 375afb9cd6cdde468e3b460b0bc0d9c7b663c38bf7b4cd41f328d98ac6806009
MD5 632ed810d8d8e145966fdfbc61a99f0c
BLAKE2b-256 71e57d7a498326b7e1327ed87e84af400a81a0ab4b54e555301106c0338fe41b

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