Skip to main content

An event-based framework

Project description

Pypi Downloads Build Discord Documentation

Streamline your Python Data Pipeline in one package

Building an all-in-one package that does api, scraping and integrates slow processing is hard.

aiosow glues this all together.

Efficient, Event-Based, Modular

  • Asynchronous

For efficient performance in I/O operations.

  • Event-based

Helps you focus on the desired outcome rather than every single step.

  • Modular

Allow each part of the codebase to be developed independently.

Enforced Separation of Concerns

aiosow encourage a structure that separate implementations from the behavior. Defined boundaries for different parts of the codebase, makes it easier to maintain and scale. As a result, aiosow can provide a set of tools that let developers interconnect and customize multiple compositions with ease.

Customizable Asynchronous State-Machine

aiosow is a programmable state-machine customizable with decorators and utilities for easy and efficient event triggering implementations. State-machines provides a way to manage the flow of a system by storing and managing mutations in the memory.

  • One global memory represented as a dict
  • Mutations are the changes, just return a dict and you got a valid mutation
  • To bind this function in the state-machine you use aiosow.bindings

These bindings allow to program the machine and express when to call the appropriate functions in the correct order, ensuring that the system behaves as expected. The state machine is a useful tool for managing complex systems and ensuring that behavior is well-defined and predictable. It allows to react to changes in the system and implement logic based on those changes (see aiosow.bindings.on for instance).

  • aiosow.bindings helps you express configurability, further data-piping, time-constraints, and more...
  • aiosow.routines helps you schedule code to flow trough time
  • aiosow.aiohttp helps with HTTP requests

Compositions

compositions are Python packages that use aiosow.bindings to define aiosow's behavior.

They follow a set of rules :

1. implementation is strictly separate from the package's behavior.
  • implementation refers to the technical aspects of how a feature is coded and developed, such as algorithms and data structures. It focuses on the "how" of software development.

Separating these two concerns helps make software more maintainable and flexible over time.

Example of implementation:

def get_data():
    return 'foo'

def capitalize(s: str):
    return s.capitalize()
2. Behaviors are defined in a behavior.py file using aiosow.bindings
  • behavior refers to the overall conduct and purpose of a software system, from the user's perspective. It focuses on the "what" and "when" of software development.

Example of behavior:

signal_data_when, on_received_data_do = wire() # build a wire for data reception
data_treated_when, on_data_ready_do = wire()   # build a wire for data that is ready

signal_data_when(get_data)                     # on data reception trigger functions registered
on_received_data_do(capitalize)                # capitalize every data that is received
data_treated_when(capitalize)                  # once data is capitalized, send it
routine(1)(get_data)                           # get some data every second
on_data_ready_do(print)                        # anytime data is ready print it
3. Function prototypes use a strict naming consistency

aiosow.bindings.autofill is the backone of the library used trough all tools to cast a function.

It is doing so by filling missing arguments from their prototype based on memory.

Example:

                `args` are poped first, `on` will pass the value that changed
                  |
                  | `foo` is autofilled, value is retrieved from `memory`
                  |   |
                  v   v
do_smtg = lambda ev, foo: print(ev, foo)
on('event')(do_smtg)                           # this will trigger do_smtg when 'bar' is set
setup(lambda : { 'foo': 'bar' })               # init 'foo' to 'bar'
setup(lambda : { 'event': 'trigger' })         # triggers `do_smtg`

> 'trigger', 'bar'

4. Implementation is low-coupled

Low coupled code refers to code that has minimal interdependencies between its different components or modules. In other words, changes to one component should not require extensive modifications to other components. This promotes modularity, maintainability, and flexibility in software development.

  • When you write an implementation, you are providing vocabulary available to the behavior expression.

Example of high-coupled code:

def calculate_total_price(quantity, unit_price):
    tax_rate = 0.1
    subtotal = quantity * unit_price
    tax_amount = subtotal * tax_rate
    total_price = subtotal + tax_amount
    return total_price

Example of low-coupled code:

def calculate_subtotal(quantity, unit_price):
    subtotal = quantity * unit_price
    return subtotal

def calculate_tax(subtotal):
    tax_rate = 0.1
    tax_amount = subtotal * tax_rate
    return tax_amount

def calculate_total_price(quantity, unit_price):
    subtotal = calculate_subtotal(quantity, unit_price)
    tax_amount = calculate_tax(subtotal)
    total_price = subtotal + tax_amount
    return total_price
5. Initialization is decoupled of processing

The principle of decoupling the setup from operation involves separating the preparation from its actual use.

This ensures

  • that changes or modifications made during setup do not interfere with the processing.
  • that the implemented vocabulary focuses on expressing how.
6. Compositions should not be blocking the main execution

compositions implementations should not contain synchronous code that blocks the main event loop, which could cause the entire application to freeze.

Instead, all I/O operations, heavy computations and blocking tasks should be executed asynchronously using the aiosow.bindings.make_async decorator. This will ensure that the event loop remains responsive and can process other tasks efficiently.

Usage

aiosow <composition>
  • You can run the aiosow -h to display all the possible options.
  • Options change based on the composition you are using

Using aiosow 'composition_name' -h will load it's options and display them in the help menu. Those are defined using the aiosow.options decorator.

Installation

pip install aiosow

Contributing

We welcome contributions to this project from anyone. If you would like to contribute, please follow these guidelines:

  • Fork the repository and create your branch from the latest main branch.
  • Make your changes, and test them thoroughly.
  • Submit a pull request describing your changes and explaining why they should be merged. Please ensure that your pull request adheres to our code of conduct.
  • Wait for a maintainer to review your pull request, and make any requested changes.
  • Once your pull request is approved, it will be merged into the main branch.

By contributing to this project, you agree to license your contribution under the project's license. If you have any questions or concerns, please reach out to us through GitHub issues.

License

This project is licensed under the MIT License

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

aiosow-0.1.2.tar.gz (20.2 kB view hashes)

Uploaded Source

Built Distribution

aiosow-0.1.2-py3-none-any.whl (16.5 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page