Module opshin.rewrite.rewrite_import_hashlib
Expand source code
import typing
from _ast import ImportFrom, AST, Store
from dataclasses import dataclass
from enum import Enum, auto
import pluthon as plt
from frozenlist2 import frozenlist
from ..typed_ast import *
from ..type_impls import ClassType, InstanceType, ByteStringInstanceType, FunctionType
from ..util import CompilingNodeTransformer, force_params
"""
Checks that there was an import of dataclass if there are any class definitions
"""
@dataclass(frozen=True, unsafe_hash=True)
class HashType(ClassType):
"""A pseudo class that is the result of python hash functions that need a 'digest' call"""
def attribute_type(self, attr) -> "Type":
if attr == "digest":
return InstanceType(FunctionType(frozenlist([]), ByteStringInstanceType))
raise NotImplementedError("HashType only has attribute 'digest'")
def attribute(self, attr) -> plt.AST:
if attr == "digest":
return plt.Lambda(["self"], plt.Var("self"))
raise NotImplementedError("HashType only has attribute 'digest'")
def __ge__(self, other):
return isinstance(other, HashType)
def python_type(self):
return "HashFunction"
HashInstanceType = InstanceType(HashType())
class PythonHashlib(Enum):
sha256 = auto()
sha3_256 = auto()
blake2b = auto()
PythonHashlibTypes = {
PythonHashlib.sha256: InstanceType(
FunctionType(
frozenlist([ByteStringInstanceType]),
HashInstanceType,
)
),
PythonHashlib.sha3_256: InstanceType(
FunctionType(
frozenlist([ByteStringInstanceType]),
HashInstanceType,
)
),
PythonHashlib.blake2b: InstanceType(
FunctionType(
frozenlist([ByteStringInstanceType]),
HashInstanceType,
)
),
}
PythonHashlibImpls = {
PythonHashlib.sha256: force_params(
plt.Lambda(["x"], plt.Lambda(["_"], plt.Sha2_256(plt.Var("x"))))
),
PythonHashlib.sha3_256: force_params(
plt.Lambda(["x"], plt.Lambda(["_"], plt.Sha3_256(plt.Var("x"))))
),
PythonHashlib.blake2b: force_params(
plt.Lambda(["x"], plt.Lambda(["_"], plt.Blake2b_256(plt.Var("x"))))
),
}
class RewriteImportHashlib(CompilingNodeTransformer):
step = "Resolving imports and usage of hashlib"
imports_hashlib = False
def visit_ImportFrom(self, node: ImportFrom) -> typing.Union[typing.List[AST], AST]:
if node.module != "hashlib":
return node
additional_assigns = []
for n in node.names:
imported_fun = None
for h in PythonHashlib:
if h.name == n.name:
imported_fun = h
assert (
imported_fun is not None
), f"Unsupported function import from hashlib '{n.name}"
typ = PythonHashlibTypes[imported_fun]
imported_name = n.name if n.asname is None else n.asname
additional_assigns.append(
TypedAssign(
targets=[TypedName(id=imported_name, typ=typ, ctx=Store())],
value=RawPlutoExpr(typ=typ, expr=PythonHashlibImpls[imported_fun]),
)
)
return additional_assigns
Classes
class HashType-
A pseudo class that is the result of python hash functions that need a 'digest' call
Expand source code
@dataclass(frozen=True, unsafe_hash=True) class HashType(ClassType): """A pseudo class that is the result of python hash functions that need a 'digest' call""" def attribute_type(self, attr) -> "Type": if attr == "digest": return InstanceType(FunctionType(frozenlist([]), ByteStringInstanceType)) raise NotImplementedError("HashType only has attribute 'digest'") def attribute(self, attr) -> plt.AST: if attr == "digest": return plt.Lambda(["self"], plt.Var("self")) raise NotImplementedError("HashType only has attribute 'digest'") def __ge__(self, other): return isinstance(other, HashType) def python_type(self): return "HashFunction"Ancestors
Methods
def attribute(self, attr) ‑> pluthon.pluthon_ast.AST-
Inherited from:
ClassType.attributeThe attributes of this class. Needs to be a lambda that expects as first argument the object itself
Expand source code
def attribute(self, attr) -> plt.AST: if attr == "digest": return plt.Lambda(["self"], plt.Var("self")) raise NotImplementedError("HashType only has attribute 'digest'") def attribute_type(self, attr) ‑> Type-
Inherited from:
ClassType.attribute_typeThe types of the named attributes of this class
Expand source code
def attribute_type(self, attr) -> "Type": if attr == "digest": return InstanceType(FunctionType(frozenlist([]), ByteStringInstanceType)) raise NotImplementedError("HashType only has attribute 'digest'") def binop(self, binop: ast.operator, other: TypedAST) ‑> pluthon.pluthon_ast.AST-
Inherited from:
ClassType.binopImplements a binary operation between self and other
def binop_type(self, binop: ast.operator, other: Type) ‑> Type-
Inherited from:
ClassType.binop_typeType of a binary operation between self and other.
def cmp(self, op: ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST-
The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …
def constr(self) ‑> pluthon.pluthon_ast.AST-
Inherited from:
ClassType.constrThe constructor for this class
def constr_type(self) ‑> InstanceType-
Inherited from:
ClassType.constr_typeThe type of the constructor for this class
def copy_only_attributes(self) ‑> pluthon.pluthon_ast.AST-
Inherited from:
ClassType.copy_only_attributesPluthon function that returns a copy of only the attributes of the object This can only be called for UnionType and RecordType, as such the input data …
def pluthon_type(self, skip_constructor: bool = False) ‑> str-
Inherited from:
ClassType.pluthon_typeReturns a representation of the type in pluthon.
def python_type(self)-
Inherited from:
ClassType.python_typeReturns a representation of the type in python.
Expand source code
def python_type(self): return "HashFunction" def rbinop(self, binop: ast.operator, other: TypedAST) ‑> pluthon.pluthon_ast.AST-
Inherited from:
ClassType.rbinopImplements the reverse binary operation between self and other (other
self) def rbinop_type(self, binop: ast.operator, other: Type) ‑> Type-
Inherited from:
ClassType.rbinop_typeType of the reversed binary operation between self and other (other
self) def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST-
Inherited from:
ClassType.stringifyReturns a stringified version of the object …
def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST-
Inherited from:
ClassType.unopImplements a unary operation on self
def unop_type(self, unop: ast.unaryop) ‑> Type-
Inherited from:
ClassType.unop_typeType of a unary operation on self.
class PythonHashlib (*args, **kwds)-
Create a collection of name/value pairs.
Example enumeration:
>>> class Color(Enum): ... RED = 1 ... BLUE = 2 ... GREEN = 3Access them by:
- attribute access:
Color.RED
- value lookup:
Color(1)
- name lookup:
Color['RED']
Enumerations can be iterated over, and know how many members they have:
>>> len(Color) 3>>> list(Color) [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.
Expand source code
class PythonHashlib(Enum): sha256 = auto() sha3_256 = auto() blake2b = auto()Ancestors
- enum.Enum
Class variables
var blake2bvar sha256var sha3_256
class RewriteImportHashlib-
A :class:
NodeVisitorsubclass that walks the abstract syntax tree and allows modification of nodes.The
NodeTransformerwill walk the AST and use the return value of the visitor methods to replace or remove the old node. If the return value of the visitor method isNone, the node will be removed from its location, otherwise it is replaced with the return value. The return value may be the original node in which case no replacement takes place.Here is an example transformer that rewrites all occurrences of name lookups (
foo) todata['foo']::class RewriteName(NodeTransformer):
def visit_Name(self, node): return Subscript( value=Name(id='data', ctx=Load()), slice=Constant(value=node.id), ctx=node.ctx )Keep in mind that if the node you're operating on has child nodes you must either transform the child nodes yourself or call the :meth:
generic_visitmethod for the node first.For nodes that were part of a collection of statements (that applies to all statement nodes), the visitor may also return a list of nodes rather than just a single node.
Usually you use the transformer like this::
node = YourTransformer().visit(node)
Expand source code
class RewriteImportHashlib(CompilingNodeTransformer): step = "Resolving imports and usage of hashlib" imports_hashlib = False def visit_ImportFrom(self, node: ImportFrom) -> typing.Union[typing.List[AST], AST]: if node.module != "hashlib": return node additional_assigns = [] for n in node.names: imported_fun = None for h in PythonHashlib: if h.name == n.name: imported_fun = h assert ( imported_fun is not None ), f"Unsupported function import from hashlib '{n.name}" typ = PythonHashlibTypes[imported_fun] imported_name = n.name if n.asname is None else n.asname additional_assigns.append( TypedAssign( targets=[TypedName(id=imported_name, typ=typ, ctx=Store())], value=RawPlutoExpr(typ=typ, expr=PythonHashlibImpls[imported_fun]), ) ) return additional_assignsAncestors
- CompilingNodeTransformer
- TypedNodeTransformer
- ast.NodeTransformer
- ast.NodeVisitor
Class variables
var imports_hashlibvar step
Methods
def visit(self, node)-
Inherited from:
CompilingNodeTransformer.visitVisit a node.
def visit_ImportFrom(self, node: ast.ImportFrom) ‑> List[ast.AST] | ast.AST-
Expand source code
def visit_ImportFrom(self, node: ImportFrom) -> typing.Union[typing.List[AST], AST]: if node.module != "hashlib": return node additional_assigns = [] for n in node.names: imported_fun = None for h in PythonHashlib: if h.name == n.name: imported_fun = h assert ( imported_fun is not None ), f"Unsupported function import from hashlib '{n.name}" typ = PythonHashlibTypes[imported_fun] imported_name = n.name if n.asname is None else n.asname additional_assigns.append( TypedAssign( targets=[TypedName(id=imported_name, typ=typ, ctx=Store())], value=RawPlutoExpr(typ=typ, expr=PythonHashlibImpls[imported_fun]), ) ) return additional_assigns