AnyFilter
AnyFilter is a simple base class for defining data filters. It provides the following functionality:
stores configurations in JSON
retains previous versions of configurations with user info and timestamp
isolates custom code
The intent is to create a subclass of the Filter class in any case where custom code has to be written. This keeps the custom code out of the primary workflow and codebase, and allows Filter subclasses to be inserted and toggled as needed, while storing configurations for the filters outside the codebase and the applications’s primary database for portability and ease of maintenance.
Motivation
The problem which led to this solution is the need to consume data from end users. Usually, and especially when the users are clients, this data can not be relied upon to meet the input specifications of your system.
This usually leads one of these sub-optimal solutions:
Have custom scripts to pre-process data per client
Adding a bunch of if statements, or other similar logic to the core product
Attempting to make transformation scripts generic enough to re-use, thus making them less useful for their primary purpose and harder to debug
Hard-coding data into transformation scripts
There is often a custom transformation per client or project, so these solutions do not scale well.
The goals of AnyFilter are:
Minimize the amount of custom code in the primary codebase
Store configurations outside the application’s database in a portable format
Allow updates of configuration data without deploying code (privileged users may even edit a configuration via some sort of GUI)
Benefits
create pluggable data filters
store configurations outside your application’s database
easily back up and restore configurations
easily duplicate configurations across servers
Planned features
Export and import configs
Convert configs to and from HTML forms for easy front-end functionality
Easily revert to a prior config
Comprehensive unit tests
Sample usage
#!/usr/bin/env python
"""
This is a simple example of the use of the Filter class. In this case, a
dictionary has some keys renamed. This is a trivial example; filters
can be as complex as required.
"""
from anyfilter import Filter
class NameFilter(Filter):
"""
A filter that changes the names of dictionary keys.
'data' should be an iterable of dictionaries
"""
def __call__(self, data):
"""
The contents of this function are the least-important part of
this demo. This is where you custom code will go, doing whatever
it is you need with whatever config format and content you need.
"""
for rec in data:
# The config for this filter is a dictionary where the
# key is the key name to replace, and the value is the new name.
# update values in "data" dict
for key, value in self.config.items():
if key in rec:
rec[value] = rec[key]
del rec[key]
return data
if __name__ == '__main__':
import os # for dealing with the environment variable manually
# set environment variable for demo purposes
original_envvar = os.environ.get('FILTER_CONFIG_DIR', '')
os.environ['FILTER_CONFIG_DIR'] = '/tmp'
# Instantiate subclass. The only argument is the uid of the subject
# of the filter. For example, if you need to store different rules
# per user of your site, you might use the user's primary key here.
# This allows storage of configs per filter *and* per user.
name_filter = NameFilter('foo')
# Set some filter items. This normally won't be a part of the flow.
# It's here for demo purposes. In normal usage, the config would
# already be set and probably rarely updated.
name_filter.config = {
'dog': 'canine',
'cat': 'feline',
'horse': 'equine',
}
name_filter.save_config(user='example')
data = [{
'cat': 'meow',
'dog': 'woof',
'horse': 'neigh',
'foo': 'bar',
}]
print data # original
print name_filter(data) # altered
# Put it back like we found it, just to be good citizens.
os.environ['FILTER_CONFIG_DIR'] = original_envvar
Sample output
[{'horse': 'neigh', 'foo': 'bar', 'dog': 'woof', 'cat': 'meow'}]
[{'equine': 'neigh', 'feline': 'meow', 'canine': 'woof', 'foo': 'bar'}]
Metadata
Release files for AnyFilter 0.05
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| AnyFilter-0.05.tar.gz | 4.3 kB | Without provenance | Details |
Release files / AnyFilter-0.05.tar.gz
| Download URL | AnyFilter-0.05.tar.gz |
|---|---|
| Size | 4.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6cfab8f426c00c54b053d915553d9af5322811064e0a08a1c3503c99bca299e4
|
|
BLAKE2b-256 checksum How to use checksums |
26b11191e68cfa99532d3739f75f07987dcd232691920558514932eba7395d39
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
Security for AnyFilter 0.05
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.
To learn more about protecting yourself from malicious actors, visit our package security documentation.