Movatterモバイル変換


[0]ホーム

URL:


Skip to main content
PyPI

codetransformer 0.7.2

pip install codetransformer

Latest version

Released:

Python code object transformers

Verified details

These details have beenverified by PyPI
Maintainers
Avatar for llllllllll from gravatar.comllllllllllAvatar for ssanderson from gravatar.comssanderson

Unverified details

These details havenot been verified by PyPI
Project links
Meta

Project description

build statusDocumentation Status

Bytecode transformers for CPython inspired by theast module’sNodeTransformer.

What iscodetransformer?

codetransformer is a library that allows us to work with CPython’s bytecoderepresentation at runtime.codetransformer provides a level of abstractionbetween the programmer and the raw bytes read by the eval loop so that we canmore easily inspect and modify bytecode.

codetransformer is motivated by the need to override parts of the pythonlanguage that are not already hooked into through data model methods. For example:

  • Override theis andnot operators.

  • Custom data structure literals.

  • Syntax features that cannot be represented with valid python AST or source.

  • Run without a modified CPython interpreter.

codetransformer was originally developed as part oflazy to implementthe transformations needed to override the code objects at runtime.

Example Uses

Overloading Literals

While this can be done as an AST transformation, we will often need to executethe constructor for the literal multiple times. Also, we need to be sure thatany additional names required to run our code are provided when we run. Withcodetransformer, we can pre compute our new literals and emit code that isas fast as loading our unmodified literals without requiring any additionalnames be available implicitly.

In the following block we demonstrate overloading dictionary syntax to result incollections.OrderedDict objects.OrderedDict is like adict;however, the order of the keys is preserved.

>>>fromcodetransformer.transformers.literalsimportordereddict_literals>>>@ordereddict_literals...deff():...return{'a':1,'b':2,'c':3}>>>f()OrderedDict([('a',1),('b',2),('c',3)])

This also supports dictionary comprehensions:

>>>@ordereddict_literals...deff():...return{k:vfork,vinzip('abc',(1,2,3))}>>>f()OrderedDict([('a',1),('b',2),('c',3)])

The next block overridesfloat literals withdecimal.Decimalobjects. These objects support arbitrary precision arithmetic.

>>>fromcodetransformer.transformers.literalsimportdecimal_literals>>>@decimal_literals...deff():...return1.5>>>f()Decimal('1.5')

Pattern Matched Exceptions

Pattern matched exceptions are a good example of aCodeTransformer thatwould be very complicated to implement at the AST level. This transformationextends thetry/except syntax to accept instances ofBaseException aswell subclasses ofBaseException. When excepting an instance, theargsof the exception will be compared for equality to determine which exceptionhandler should be invoked. For example:

>>>@pattern_matched_exceptions()...deffoo():...try:...raiseValueError('bar')...exceptValueError('buzz'):...return'buzz'...exceptValueError('bar'):...return'bar'>>>foo()'bar'

This function raises an instance ofValueError and attempts to catch it. Thefirst check looks for instances ofValueError that were constructed with anargument of'buzz'. Because our custom exception is raised with'bar',these are not equal and we do not enter this handler. The next handler looks forValueError('bar') which does match the exception we raised. We then enterthis block and normal python rules take over.

We may also pass their own exception matching function:

>>>defmatch_greater(match_expr,exc_type,exc_value,exc_traceback):...returnmath_expr>exc_value.args[0]>>>@pattern_matched_exceptions(match_greater)...deffoo():...try:...raiseValueError(5)...except4:...return4...except5:...return5...except6:...return6>>>foo()6

This matches on when the match expression is greater in value than the firstargument of any exception type that is raised. This particular behavior would bevery hard to mimic through AST level transformations.

Core Abstractions

The three core abstractions ofcodetransformer are:

  1. TheInstruction object which represents anopcode which may be pairedwith some argument.

  2. TheCode object which represents a collection ofInstructions.

  3. TheCodeTransformer object which represents a set of rules formanipulatingCode objects.

Instructions

TheInstruction object represents an atomic operation that can be performedby the CPython virtual machine. These are things likeLOAD_NAME which loadsa name onto the stack, orROT_TWO which rotates the top two stack elements.

Some instructions accept an argument, for exampleLOAD_NAME, which modifiesthe behavior of the instruction. This is much like a function call where somefunctions accept arguments. Because the bytecode is always packed as raw bytes,the argument must be some integer (CPython stores all arguments two in bytes).This means that things that need a more rich argument system (likeLOAD_NAMEwhich needs the actual name to look up) must carry around the actual argumentsin some table and use the integer as an offset into this array. One of the keyabstractions of theInstruction object is that the argument is always somepython object that represents the actual argument. Any lookup table managementis handled for the user. This is helpful because some arguments share this tableso we don’t want to add extra entries or forget to add them at all.

Another annoyance is that the instructions that handle control flow use theirargument to say what bytecode offset to jump to. Some jumps use the absoluteindex, others use a relative index. This also makes it hard if you want to addor remove instructions because all of the offsets must be recomputed. Incodetransformer, the jump instructions all accept anotherInstruction asthe argument so that the assembler can manage this for the user. We also providean easy way for new instructions to “steal” jumps that targeted anotherinstruction so that can manage altering the bytecode around jump targets.

Code

Code objects are a nice abstraction over python’stypes.CodeType. Quoting theCodeType constructor docstring:

code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring,      constants, names, varnames, filename, name, firstlineno,      lnotab[, freevars[, cellvars]])Create a code object.  Not for the faint of heart.

Thecodetransformer abstraction is designed to make it easy to dynamicallyconstruct and inspect these objects. This allows us to easy set things like theargument names, and manipulate the line number mappings.

TheCode object provides methods for converting to and from Python’s coderepresentation:

  1. from_pycode

  2. to_pycode.

This allows us to take an existing function, parse the meaning from it, modifyit, and then assemble this back into a new python code object.

Note

Code objects are immutable. When we say “modify”, we mean create a copywith different values.

CodeTransformers

This is the set of rules that are used to actually modify theCodeobjects. These rules are defined as a set ofpatterns which are a DSL usedto define a DFA for matching against sequences ofInstruction objects. Oncewe have matched a segment, we yield new instructions to replace what we havematched. A simple codetransformer looks like:

fromcodetransformerimportCodeTransformer,instructionsclassFoldNames(CodeTransformer):@pattern(instructions.LOAD_GLOBAL,instructions.LOAD_GLOBAL,instructions.BINARY_ADD,)def_load_fast(self,a,b,add):yieldinstructions.LOAD_FAST(a.arg+b.arg).steal(a)

ThisCodeTransformer uses the+ operator to implement something likeCPPs token pasting for local variables. We read this pattern as a sequenceof twoLOAD_GLOBAL (global name lookups) followed by aBINARY_ADDinstruction (+ operator call). This will then call the function with thethree instructions passed positionally. This handler replaces this sequence witha single instruction that emits aLOAD_FAST (local name lookup) that is theresult of adding the two names together. We then steal any jumps that used totarget the firstLOAD_GLOBAL.

We can execute this transformer by calling an instance of it on afunction object, or using it like a decorator. For example:

>>>@FoldNames()...deff():...ab=3...returna+b>>>f()3

License

codetransformer is free software, licensed under the GNU General PublicLicense, version 2. For more information see theLICENSE file.

Source

Source code is hosted on github athttps://github.com/llllllllll/codetransformer.

Project details

Verified details

These details have beenverified by PyPI
Maintainers
Avatar for llllllllll from gravatar.comllllllllllAvatar for ssanderson from gravatar.comssanderson

Unverified details

These details havenot been verified by PyPI
Project links
Meta

Download files

Download the file for your platform. If you're not sure which to choose, learn more aboutinstalling packages.

Source Distribution

codetransformer-0.7.2.tar.gz (73.6 kBview details)

UploadedSource

File details

Details for the filecodetransformer-0.7.2.tar.gz.

File metadata

File hashes

Hashes for codetransformer-0.7.2.tar.gz
AlgorithmHash digest
SHA256442aca89cc961f8c9234dd17e35d36cdeaca670f167610e67cef232426705118
MD51ca91458bc5a82d9f3f1a5b468af785c
BLAKE2b-2567bde7b1dc2314b04b7d3a6ab3d1e0c2e24b3db51f9147dbcde5bd3840475368b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security SponsorDatadog MonitoringDepot Continuous IntegrationFastly CDNGoogle Download AnalyticsPingdom MonitoringSentry Error loggingStatusPage Status page

[8]ページ先頭

©2009-2026 Movatter.jp