Skip to main content

aspectp

Aspect Oriented Programming in Python.

Aspect-Oriented Programming (AOP) is a programming paradigm that separates cross-cutting concerns, like logging or security, from the main code to improve modularity and code organization, making it easier to manage and maintain complex software systems.

Intallation

pip install aspectp

Example

import aspectp
import math

def add_one(result):
    return result + 1

print(math.pow(2, 2)) # 4.0
aspectp.after(math.pow, add_one)
print(math.pow(2, 2)) # 5.0

Background

Aspect

An aspect is a modular unit that encapsulates a specific cross-cutting concern. Cross-cutting concerns are features or behaviors that span across multiple parts of a program, such as logging, error handling, or transaction management. Aspects allow these concerns to be added to existing code without modifying the code itself.

Joinpoint

A joinpoint is a point in the execution of the program, such as a function/method call, or an exception being thrown. A joinpoint is the place where an advice is attached. The following joinpoints are supported:

  • function
  • method
  • object: the advice is attached to all methods of the object
  • class: the advice is attached to all methods of the class
  • module: the advice is attached to all functions in the module

Advice

An advice is the action taken by an aspect at a specific joinpoint. There are 4 kinds of advices:

  • before: executed before a joinpoint
  • after: exectuted after a joinpoint
  • around: executed before and after a joinpoint
  • error: executed when a joinpoint raises an error

Usage

Before

To attach before a joinpoint execution use:

aspectp.before(joinpoint, before_advice)

Where before_advice is a function with the following signature:

def before_advice(args, kwargs):
    # Do stuff
    return args, kwargs

before_advice can read and modify the arguments that will be passed to joinpoint. before_advice can also throw an exception to prevent joinpoint from being executed.

Here is an example of aspectp.before:

import aspectp
import math

def increase_exponent(args, kwargs):
    return (args[0], args[1] + 1), kwargs

print(math.pow(2, 2)) # 4.0
aspectp.before(math.pow, increase_exponenet)
print(math.pow(2, 2)) # 8.0

After

To attach after a joinpoint execution use:

aspectp.after(joinpoint, after_advice)

Where after_advice is a function with the following signature:

def after_advice(result):
    # Do stuff
    return result

after_advice can read and modify the result returned by joinpoint. after_advice can also throw an exception to prevent result from being returned.

Here is an example of aspectp.after:

import aspectp
import math

def increase_result(result):
    return result + 1

print(math.pow(2, 2)) # 4.0
aspectp.after(math.pow, increase_result)
print(math.pow(2, 2)) # 5.0

Around

Attaching around a joinpoint is similar to attaching before and after a joinpoint. To attach around a joinpoint execution use:

aspectp.around(joinpoint, around_advice)

Where around_advice is a function with the following signature:

def around_advice(func, args, kwargs):
    # Do stuff
    result = func(args, kwargs)
    # Do stuff
    return result

around_advice is responsible for calling func, which will execute the joinpoint. around_advice can read and modify the arguments. around_advice can prevent joinpoint from being executed by not calling func. around_advice can read and modify the result.

Here is an example of aspectp.around:

import aspectp
import math

def increase_exponent_and_result(func, args, kwargs):
    result = func((args[0], args[1] + 1), kwargs)
    return result + 1

print(math.pow(2, 2)) # 4.0
aspectp.around(math.pow, increase_exponent_and_result)
print(math.pow(2, 2)) # 9.0

Error

To attach after a joinpoint raises an error use:

aspectp.error(joinpoint, error_advice)

Where error_advice is a function with the following signature:

def error_advice(error):
    # Do stuff
    return error

error_advice can handle the error raised by joinpoint. error_advice does not need to return error.

Here is an example of aspectp.error:

import aspectp
import math

def return_zero_on_error(error):
    return 0.0
try:
    math.sqrt(-1)
except ValueError as e:
    print(e) # math domain error
aspectp.error(math.sqrt, return_zero_on_error)
print(math.sqrt(-1)) # 0.0

Remove

To remove all advices from a joinpoint use:

aspectp.remove(joinpoint)

To remove a single advice from a joinpoint use:

id = aspectp.before(joinpoint, before_advice)
# Do stuff
aspectp.remove(joinpoint, id)

Notes

  • The order in which advices are executed is: before_advice, around_advice, after_advice
  • At any point, if an error is raised and an error_advice exists, the error_advice is called
  • Multiple advices of the same kind can be attached to the same joinpoint, and they are executed in the orther that they are defined
  • The argument func in around_advice is not the actual joinpoint, but it is a wrapper.
  • When attaching an advice to a joinpoint, aspectp replaces the joinpoint with a special function that wraps the joinpoint

Metadata

Release files for aspectp 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aspectp 1.0.1
File Size Uploaded Provenance Actions
aspectp-1.0.1.tar.gz 17.7 kB Without provenance Details for aspectp-1.0.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for aspectp 1.0.1
File Interpreter ABI Platform Actions
aspectp-1.0.1-py3-none-any.whl Python 3 none any Details for aspectp-1.0.1-py3-none-any.whl

Total release size: 34.0 kB

Release files / aspectp-1.0.1.tar.gz

Download URL aspectp-1.0.1.tar.gz
Size 17.7 kB
Tags Source
SHA-256 checksum
How to use checksums
fe8d45a6c879d7bc6ced19ceb01a8a703bde573a8844ea9c5426528fa3a92412
BLAKE2b-256 checksum
How to use checksums
a82f6b5f82413a16fcebac4794e7ce8d28796772584178c3f8a73903c716cdee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.11.0

Release files / aspectp-1.0.1-py3-none-any.whl

Download URL aspectp-1.0.1-py3-none-any.whl
Size 16.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1791a16a1b88ceb437e541ad5ab3bfcc75f8594b3044858b2003d4ac7707c523
BLAKE2b-256 checksum
How to use checksums
2108eb19fbdc60b2787c6a345fcc14aa1f55fadb37e653a9c2a900eaa3dc7425
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.11.0

Security for aspectp 1.0.1

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.

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page