a framework to help you stay on top of what data is flowing through your code.
Project description
:moyai: pyalert
pyalert
is a lightweight framework that empowers you to stay on top of what data is flowing through your Python code.
pyalert
is designed to:
- mimic the feeling of writing unit tests
- unobtrusively add runtime alerting to your Python code
:mag: Table of Contents
- :gear: How Does It Work?
- :memo: In Summary
- :brain: Further Thinking
- :construction: Roadmap
- :handshake: Contribution
:gear: How Does It Work?
Suppose you are building software that involves processing data from a bike race...
class Biker:
def __init__(self, name: str, age: int, avg_mph: int):
self.name = name
self.age = age
self.avg_mph = avg_mph
def bike_race(bikers: List[Biker]) -> str:
"""A bike race that takes three Bikers and returns a winner announcement"""
winner = max(bikers, key=lambda biker: biker.avg_mph)
return f"{winner.name} wins with an avg mph of {winner.avg_mph}!"
Instead of cluttering your code with complex catching logic and log
/print
statements to indicate when certain occurances arise, pyalert
facilitates an intuitive segregation of such concerns with a unit-test-like design pattern...
As is often done with unit tests, let's define a class that contains our alerts...
Note how we use the @alert_conf
decorator to configure the runtime behavior of each alert method...
from pyalert import PyAlerts, alert_conf
# must inherit from PyAlerts
class BikeRaceAlerts(PyAlerts):
"""Alerts for the bike_race function"""
# takes="input" configures the alert method to take the input args as its args
@alert_conf(takes="input", raise_error=False)
def suspiciously_fast_bikers(self, *args, **kwargs):
bikers = args[0] if args else kwargs["bikers"]
msg = "Suspicious speeds--implement compulsory drug testing after the race!"
assert not any(b.avg_mph > 30), msg
# raise_error=True will cause an error to be raised if the assertion fails
@alert_conf(takes="input", raise_error=True)
def impossibly_fast_bikers(self, *args, **kwargs):
bikers = args[0] if args else kwargs["bikers"]
msg = "Stop the race! we need to recalibrate our speedometers!"
assert not any(b.avg_mph > 100 for b in bikers), msg
# takes="output" configures the alert method to take the return value as its arg
@alert_conf(takes="output", raise_error=False)
def verbose_winner_announcement(self, return_value):
msg = "The winner announcement came out unusually verbose!"
assert len(return_value) < 120, msg
Lastly, we'll decorate our original bike_race
function with the @pyalert
decorator and pass BikeRaceAlerts
as the argument:
from pyalert import pyalert
@pyalert(pyalerts=BikeRaceAlerts)
def bike_race(bikers: List[Biker]) -> str:
...
And voila, pyalerts
will take care of our alerts at runtime!
:memo: In Summary
pyalert
has 3 fundamental abstractions...
flowchart TD
pkg("📦 pyalert")
pa("1️⃣\n@pyalert\n(decorator)")
PA("2️⃣\nPyAlerts\n(base class)")
ac("3️⃣\n@alert_conf\n(decorator)")
pkg --- pa
pkg --- PA
pkg --- ac
They are used as follows:
flowchart LR
pa("1️⃣\n@pyalert\n(decorator)\n📦")
yPA("PyAlerts\nchild\nclass\n👤")
PA("2️⃣\nPyAlerts\n(base class)\n📦")
am("alert\nmethods\n👤")
yf("your\nfunction\n👤")
as("assert\nstatements\n🐍")
ac("3️⃣\n@alert_conf\n(decorator)\n📦")
pa -. takes a --> yPA
pa -. and\ndecorates --> yf
yPA -. and which\ncontains --> am
yPA -. which\ninherits\nfrom --> PA
am -. that use --> as
am -. and are\nconfigured\nby --> ac
:brain: Further Thinking
====== :thought_balloon: :one: ======
pyalerts
is designed to enhance your project by:
- :desktop_computer: - helping drive development with quicker insights
- :eye: - helping with the monitoring of data phenomena in production
...all while introducing minimal boilerplate to your source code.
====== :thought_balloon: :two: ======
pyalerts
can be used minimally as a mere seperation-of-tasks practice within a single file...
or
...since it feels so much like unit testing, why not create an alerts
folder that mirrors your src
code folder structure?
📦project
┣ 📂src
┣ 📂tests
┣ 📂alerts
┣ 📜README.md
┗ 📜requirements.txt
====== :thought_balloon: :three: ======
Are you inheriting a codebase that is already jam-packed with verbosity and complexity?
Since the only boilerplate required to use pyalerts
is a simple @pyalert
decorator, you can easily add it to your codebase without worrying about the repurcussions.
:construction: Roadmap
- :exclamation: Conceive/implement integration strategy with logging
- :exclamation: CI pipeline
- :exclamation: Docs
:handshake: Contribution
If you think there is open-source merit to this idea, or have any thoughts on how its proposed utility might be nullified by other existing tools, please let me know!
Here is a single-question form where you can voice your enthusiasm about the idea of pyalert being developed/maintained on a scale of 1-10.
If you would like contribute and collaborate, please reach out to me on LinkedIn!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file pyalert-0.0.2.tar.gz
.
File metadata
- Download URL: pyalert-0.0.2.tar.gz
- Upload date:
- Size: 5.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.10.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | bf1cbb17662f59403582502dbd3eff64bb1d186586c98994a094f07f924dc268 |
|
MD5 | 32843274698569d67e4777a2d226d18f |
|
BLAKE2b-256 | 01ac9035742d920b73afb06a8e8720aa62c66c0e25c1cfe1d1e4dc71a9a6b48b |
File details
Details for the file pyalert-0.0.2-py3-none-any.whl
.
File metadata
- Download URL: pyalert-0.0.2-py3-none-any.whl
- Upload date:
- Size: 5.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.10.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9dab7e8253891d5e4399ca2dc69bbee4d881b30bb008cca876bf8ea691b485a2 |
|
MD5 | 01e4412ad1aada970ee4e3614e968118 |
|
BLAKE2b-256 | cb62f34eb85827e9dc63491bf748d0c0fbcedb55079a9deb46a99f7d36a13f2f |