Skip to main content

Instrument code to support obj.__preassign__ / obk.__postassign__ methods. Based on assign package by ryankung

Project description

Description

assignhooks allows you to instrument your python code so that assignments to a variable can execute an action before and/or after the fact. For instance:

class SampleClass():

   name = ''

   def __assignpre__(self, lhs_name, rhs_name, rhs):
       print('PRE: assigning %s = %s' % (lhs_name, rhs_name))
       # modify rhs if needed before assignment
       rhs.name = lhs_name
       return rhs

   def __assignpost__(self, lhs_name, rhs_name):
       print('POST: lhs', self)
       print('POST: lhs_name', lhs_name)
       print('POST: rhs_name', rhs_name)
       print('POST: assigning %s = %s' % (lhs_name, rhs_name))
       self.name = lhs_name

b = SampleClass()
c = b

The first assignment would generate a call to __assignpost__ as b still has no contents so there is no information on its class and hence no way to find out if it has an __assignpre__ method. __assignpost__ allows b to find out its name in this case. In the example above b contains a SampleClass instance whose name is initialized to b (the variable name)

In the second assignment, b is being assigned on the right-hand-side. As b is already existing we can check if its class provides an __assignpre__ implementation. b knows is being assigned before the fact so we can used __assignpre__ to check on the assignment or to provide the suitable value to be assigned (the return from __assignpre__ method)

Applications:

  • Can be used to add automatically names to created objects, for debug for instance:

 class MyClass:

     def __init__(self, val, name=None):
         self.val = val
         self.name = name

     def __assignpost__(self, lhs_name, rhs_name):
         if self.name is None:
             self.name = lhs_name

# will assign x.name as 'x' automatically
x = MyClass(val=4)
assert x.name == 'x'
  • Can be used to control what gets assigned when a specific instance of a class is assigned

How to use it:

Checkout test.py and testmod.py under examples directory. test.py contains an example of how to instrument and use testmod.py module (the module being object of instrumentation).

  1. Automatic patch

Suppose that there is a testmod.py that contains a module to instrument. Importing ‘assignhooks’ gives access to ‘assignhooks.instrument.start()’. It should be called before the imports you want to instrument. To stop this behavior invoke assignhooks.instrument.stop()

Assuming testmod.py contains:

<testmod.py>

class T():
   def __assignpre__(self, lhs_name, rhs_name, rhs):
       print('%s has been copied to %s' % (rhs_name, lhs_name))
       return rhs

b = T()
c = b

And <test.py>

import assignhooks

assignhooks.instrument.start() # instrument from now on

import testmod

assignhooks.instrument.stop() # stop instrumenting

If executed:

$ python3 ./test.py

will produce

b has been copied to c

  1. manually patch

from assignhooks.patch import patch_module
import testmod

patch_module(test)

Install

Just do:

pip3 install assignhooks

How does it work

Internally assignhooks.magic replaces __import__ by a new version that after the import patches the module AST tree. It performs the following transformations:

x = T()

gets replaced by:

if True:
    x = T()
    if hasattr(x, '__assignpost__'):
        x.__assignpost__('x', 'T')

and

x = y

gets replaced by:

if True:
    if hasattr(y, '__assignpre__'):
        x = y.__assignpre__('x', 'y', y)
    else:
        x = y
    if hasattr(x, '__assignpost__'):
        x.__assignpost__('x', 'y')

NOTE: that if True: is only used to group the statements while doing node replacements in the AST.

Notes

  • Tested with Python 3.8.7 on MacOS

Credits

Based on original code from assign module from ryankung. Mainly adapted for my needs to handle object creation. Changes include:

  • Original had an __assign__ overload only valid on existing objects (like __assignpre__). Added __assignpost__ to handle object creation cases

  • Renamed __assign__ to __assignpre__ and added extra parameters

Known Issues

  1. Won’t work under REPL

  2. May slow down import operation. The effect in run-time is the replacement of raw assignments with conditional + assignment + hook

  3. May fail when patching standard modules

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

assignhooks-1.0.1.tar.gz (7.1 kB view hashes)

Uploaded Source

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