[SEBA-412] Automated reformat of Python code
Passes of modernize, autopep8, black, then check with flake8
flake8 + manual fixes:
lib/xos-config
lib/xos-kafka
lib/xos-util
xos/coreapi
xos/api
xos/xos_client
Change-Id: Ib23cf84cb13beb3c6381fa0d79594dc9131dc815
diff --git a/lib/xos-genx/xosgenx/jinja2_extensions/fol2.py b/lib/xos-genx/xosgenx/jinja2_extensions/fol2.py
index 73d04af..6d66117 100644
--- a/lib/xos-genx/xosgenx/jinja2_extensions/fol2.py
+++ b/lib/xos-genx/xosgenx/jinja2_extensions/fol2.py
@@ -1,4 +1,3 @@
-
# Copyright 2017-present Open Networking Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,6 +13,7 @@
# limitations under the License.
+from __future__ import print_function
import astunparse
import ast
import random
@@ -21,18 +21,22 @@
import jinja2
from plyxproto.parser import *
-BINOPS = ['|', '&', '->']
-QUANTS = ['exists', 'forall']
+BINOPS = ["|", "&", "->"]
+QUANTS = ["exists", "forall"]
+
class PolicyException(Exception):
pass
+
class ConstructNotHandled(Exception):
pass
+
class TrivialPolicy(Exception):
pass
+
class AutoVariable:
def __init__(self, base):
self.base = base
@@ -42,25 +46,29 @@
return self
def next(self):
- var = 'i%d' % self.idx
+ var = "i%d" % self.idx
self.idx += 1
return var
+
def gen_random_string():
- return ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(5))
+ return "".join(
+ random.choice(string.ascii_lowercase + string.digits) for _ in range(5)
+ )
+
class FOL2Python:
def __init__(self, context_map=None):
# This will produce i0, i1, i2 etc.
- self.loopvar = iter(AutoVariable('i'))
- self.verdictvar = iter(AutoVariable('result'))
+ self.loopvar = iter(AutoVariable("i"))
+ self.verdictvar = iter(AutoVariable("result"))
self.loop_variable = self.loopvar.next()
self.verdict_variable = self.verdictvar.next()
self.context_map = context_map
if not self.context_map:
- self.context_map = {'user': 'self', 'obj': 'obj'}
+ self.context_map = {"user": "self", "obj": "obj"}
def loop_next(self):
self.loop_variable = self.loopvar.next()
@@ -72,12 +80,12 @@
pass
def format_term_for_query(self, model, term, django=False):
- if term.startswith(model + '.'):
+ if term.startswith(model + "."):
term = term[len(model) + 1:]
if django:
- term = term.replace('.', '__')
+ term = term.replace(".", "__")
else:
- term = '__elt' + '.' + term
+ term = "__elt" + "." + term
return term
def fol_to_python_filter(self, model, e, django=False, negate=False):
@@ -89,109 +97,114 @@
if django:
if negate:
# De Morgan's negation
- q_bracket = '~Q(%s)'
- or_expr = ','
- and_expr = '|'
+ q_bracket = "~Q(%s)"
+ or_expr = ","
+ and_expr = "|"
else:
- q_bracket = 'Q(%s)'
- or_expr = '|'
- and_expr = ','
+ q_bracket = "Q(%s)"
+ or_expr = "|"
+ and_expr = ","
else:
if negate:
# De Morgan's negation
- q_bracket = 'not %s'
- or_expr = ' and '
- and_expr = ' or '
+ q_bracket = "not %s"
+ or_expr = " and "
+ and_expr = " or "
else:
- q_bracket = '%s'
- or_expr = ' or '
- and_expr = ' and '
+ q_bracket = "%s"
+ or_expr = " or "
+ and_expr = " and "
- if k in ['=','in']:
- v = [self.format_term_for_query(
- model, term, django=django) for term in v]
+ if k in ["=", "in"]:
+ v = [self.format_term_for_query(model, term, django=django) for term in v]
if django:
- operator_map = {'=':' = ','in':'__in'}
+ operator_map = {"=": " = ", "in": "__in"}
else:
- operator_map = {'=':' == ','in':'in'}
+ operator_map = {"=": " == ", "in": "in"}
operator = operator_map[k]
return [q_bracket % operator.join(v)]
- elif k == '|':
- components = [self.fol_to_python_filter(
- model, x, django=django).pop() for x in v]
+ elif k == "|":
+ components = [
+ self.fol_to_python_filter(model, x, django=django).pop() for x in v
+ ]
return [or_expr.join(components)]
- elif k == '&':
- components = [self.fol_to_python_filter(
- model, x, django=django).pop() for x in v]
+ elif k == "&":
+ components = [
+ self.fol_to_python_filter(model, x, django=django).pop() for x in v
+ ]
return [and_expr.join(components)]
- elif k == '->':
- components = [self.fol_to_python_filter(
- model, x, django=django).pop() for x in v]
- return ['~%s | %s' % (components[0], components[1])]
+ elif k == "->":
+ components = [
+ self.fol_to_python_filter(model, x, django=django).pop() for x in v
+ ]
+ return ["~%s | %s" % (components[0], components[1])]
""" Convert a single leaf node from a string
to an AST"""
+
def str_to_ast(self, s):
ast_module = ast.parse(s)
return ast_module.body[0]
def reduce_operands(self, operands):
- if operands[0] in ['True','False']:
- return (operands[0],operands[1])
- elif operands[1] in ['True','False']:
- return (operands[1],operands[0])
+ if operands[0] in ["True", "False"]:
+ return (operands[0], operands[1])
+ elif operands[1] in ["True", "False"]:
+ return (operands[1], operands[0])
else:
return None
""" Simplify binops with constants """
+
def simplify_binop(self, binop):
- (k,v), = binop.items()
- if k == '->':
+ (k, v), = binop.items()
+ if k == "->":
lhs, rhs = v
- if lhs == 'True':
+ if lhs == "True":
return rhs
- elif rhs == 'True':
- return 'True'
- elif lhs == 'False':
- return 'True'
- elif rhs == 'False':
- return {'not': lhs}
+ elif rhs == "True":
+ return "True"
+ elif lhs == "False":
+ return "True"
+ elif rhs == "False":
+ return {"not": lhs}
var_expr = self.reduce_operands(v)
- if not var_expr: return binop
+ if not var_expr:
+ return binop
else:
constant, var = var_expr
- if k=='|':
- if constant=='True':
- return 'True'
- elif constant=='False':
+ if k == "|":
+ if constant == "True":
+ return "True"
+ elif constant == "False":
return var
else:
raise Exception("Internal error - variable read as constant")
- elif k=='&':
- if constant=='True':
+ elif k == "&":
+ if constant == "True":
return var
- elif constant=='False':
- return 'False'
+ elif constant == "False":
+ return "False"
def is_constant(self, var, fol):
try:
(k, v), = fol.items()
except AttributeError:
- k = 'term'
+ k = "term"
v = fol
-
- if k in ['python', 'policy']:
- # Treat as a constant and hoist, since it cannot be quantified
- return True
- elif k == 'term':
+
+ if k in ["python", "policy"]:
+ # Treat as a constant and hoist, since it cannot be quantified
+ return True
+ elif k == "term":
return not v.startswith(var)
- elif k == 'not':
+ elif k == "not":
return self.is_constant(var, fol)
- elif k in ['in', '=']:
+ elif k in ["in", "="]:
lhs, rhs = v
- return self.is_constant(var,lhs) and self.is_constant(var, rhs)
+ return self.is_constant(var, lhs) and self.is_constant(var, rhs)
elif k in BINOPS:
lhs, rhs = v
return self.is_constant(lhs, var) and self.is_constant(rhs, var)
@@ -205,21 +218,21 @@
try:
(k, v), = fol.items()
except AttributeError:
- k = 'term'
+ k = "term"
v = fol
- if k in ['python', 'policy']:
- # Treat as a constant and hoist, since it cannot be quantified
- if fol not in constants:
- constants.append(fol)
- return constants
- elif k == 'term':
- if not v.startswith(var):
- constants.append(v)
- return constants
- elif k == 'not':
+ if k in ["python", "policy"]:
+ # Treat as a constant and hoist, since it cannot be quantified
+ if fol not in constants:
+ constants.append(fol)
+ return constants
+ elif k == "term":
+ if not v.startswith(var):
+ constants.append(v)
+ return constants
+ elif k == "not":
return self.find_constants(var, v, constants)
- elif k in ['in', '=']:
+ elif k in ["in", "="]:
lhs, rhs = v
if isinstance(lhs, str) and isinstance(rhs, str):
if not lhs.startswith(var) and not rhs.startswith(var):
@@ -235,32 +248,34 @@
return constants
elif k in QUANTS:
is_constant = self.is_constant(var, v[1])
- if is_constant: constants.append(fol)
+ if is_constant:
+ constants.append(fol)
return constants
else:
raise ConstructNotHandled(k)
""" Hoist constants out of quantifiers. Depth-first. """
+
def hoist_outer(self, fol):
try:
(k, v), = fol.items()
except AttributeError:
- k = 'term'
+ k = "term"
v = fol
- if k in ['python', 'policy']:
- # Tainted, optimization and distribution not possible
- return fol
- elif k == 'term':
- return fol
- elif k == 'not':
+ if k in ["python", "policy"]:
+ # Tainted, optimization and distribution not possible
+ return fol
+ elif k == "term":
+ return fol
+ elif k == "not":
vprime = self.hoist_outer(v)
- return {'not': vprime}
- elif k in ['in', '=']:
+ return {"not": vprime}
+ elif k in ["in", "="]:
lhs, rhs = v
rlhs = self.hoist_outer(lhs)
rrhs = self.hoist_outer(rhs)
- return {k:[rlhs,rrhs]}
+ return {k: [rlhs, rrhs]}
elif k in BINOPS:
lhs, rhs = v
rlhs = self.hoist_outer(lhs)
@@ -271,7 +286,7 @@
return fol_simplified
elif k in QUANTS:
rexpr = self.hoist_outer(v[1])
- return self.hoist_quant(k, [v[0],rexpr])
+ return self.hoist_quant(k, [v[0], rexpr])
else:
raise ConstructNotHandled(k)
@@ -282,27 +297,29 @@
try:
(k, v), = fol.items()
except AttributeError:
- k = 'term'
+ k = "term"
v = fol
- if k == 'term':
- if v == c: return value
- else: return v
- elif k == 'not':
+ if k == "term":
+ if v == c:
+ return value
+ else:
+ return v
+ elif k == "not":
new_expr = self.replace_const(v, c, value)
- if new_expr=='True':
- return 'False'
- elif new_expr=='False':
- return 'True'
- else:
- return {'not': new_expr}
- elif k in ['in', '=']:
+ if new_expr == "True":
+ return "False"
+ elif new_expr == "False":
+ return "True"
+ else:
+ return {"not": new_expr}
+ elif k in ["in", "="]:
lhs, rhs = v
rlhs = self.replace_const(lhs, c, value)
rrhs = self.replace_const(rhs, c, value)
- if rlhs==rrhs:
- return 'True'
+ if rlhs == rrhs:
+ return "True"
else:
return {k: [rlhs, rrhs]}
elif k in BINOPS:
@@ -310,12 +327,12 @@
rlhs = self.replace_const(lhs, c, value)
rrhs = self.replace_const(rhs, c, value)
-
- return self.simplify_binop({k:[rlhs,rrhs]})
+
+ return self.simplify_binop({k: [rlhs, rrhs]})
elif k in QUANTS:
var, expr = v
new_expr = self.replace_const(expr, c, value)
- if new_expr in ['True', 'False']:
+ if new_expr in ["True", "False"]:
return new_expr
else:
return {k: [var, new_expr]}
@@ -323,16 +340,16 @@
raise ConstructNotHandled(k)
def shannon_expand(self, c, fol):
- lhs = self.replace_const(fol, c, 'True')
- rhs = self.replace_const(fol, c, 'False')
- not_c = {'not': c}
- rlhs = {'&': [c, lhs]}
+ lhs = self.replace_const(fol, c, "True")
+ rhs = self.replace_const(fol, c, "False")
+ not_c = {"not": c}
+ rlhs = {"&": [c, lhs]}
rlhs = self.simplify_binop(rlhs)
- rrhs = {'&': [not_c, rhs]}
+ rrhs = {"&": [not_c, rhs]}
rrhs = self.simplify_binop(rrhs)
- combined = {'|': [rlhs, rrhs]}
+ combined = {"|": [rlhs, rrhs]}
return self.simplify_binop(combined)
def hoist_quant(self, k, expr):
@@ -418,17 +435,24 @@
if not tag:
tag = gen_random_string()
- policy_function_name_template = 'policy_%s_' + '%(random_string)s' % {'random_string': tag}
+ policy_function_name_template = "policy_%s_" + "%(random_string)s" % {
+ "random_string": tag
+ }
policy_function_name = policy_function_name_template % policy_name
self.verdict_next()
function_str = """
def %(fn_name)s(obj, ctx):
if not %(vvar)s: raise XOSValidationError("%(message)s".format(obj=obj, ctx=ctx))
- """ % {'fn_name': policy_function_name, 'vvar': self.verdict_variable, 'message': message}
+ """ % {
+ "fn_name": policy_function_name,
+ "vvar": self.verdict_variable,
+ "message": message,
+ }
function_ast = self.str_to_ast(function_str)
- policy_code = self.gen_test(policy_function_name_template, fol, self.verdict_variable)
-
+ policy_code = self.gen_test(
+ policy_function_name_template, fol, self.verdict_variable
+ )
function_ast.body = [policy_code] + function_ast.body
@@ -438,17 +462,24 @@
if not tag:
tag = gen_random_string()
- policy_function_name_template = '%s_' + '%(random_string)s' % {'random_string': tag}
+ policy_function_name_template = "%s_" + "%(random_string)s" % {
+ "random_string": tag
+ }
policy_function_name = policy_function_name_template % policy_name
self.verdict_next()
function_str = """
def %(fn_name)s(obj, ctx):
return %(vvar)s
- """ % {'fn_name': policy_function_name, 'vvar': self.verdict_variable}
+ """ % {
+ "fn_name": policy_function_name,
+ "vvar": self.verdict_variable,
+ }
function_ast = self.str_to_ast(function_str)
- policy_code = self.gen_test(policy_function_name_template, fol, self.verdict_variable)
+ policy_code = self.gen_test(
+ policy_function_name_template, fol, self.verdict_variable
+ )
function_ast.body = [policy_code] + function_ast.body
@@ -456,11 +487,14 @@
def gen_test(self, fn_template, fol, verdict_var, bindings=None):
if isinstance(fol, str):
- return self.str_to_ast('%(verdict_var)s = %(constant)s' % {'verdict_var': verdict_var, 'constant': fol})
+ return self.str_to_ast(
+ "%(verdict_var)s = %(constant)s"
+ % {"verdict_var": verdict_var, "constant": fol}
+ )
(k, v), = fol.items()
- if k == 'policy':
+ if k == "policy":
policy_name, object_name = v
policy_fn = fn_template % policy_name
@@ -470,39 +504,48 @@
else:
# Everybody has access to null objects
%(verdict_var)s = True
- """ % {'verdict_var': verdict_var, 'policy_fn': policy_fn, 'object_name': object_name}
+ """ % {
+ "verdict_var": verdict_var,
+ "policy_fn": policy_fn,
+ "object_name": object_name,
+ }
call_ast = self.str_to_ast(call_str)
return call_ast
- if k == 'python':
+ if k == "python":
try:
expr_ast = self.str_to_ast(v)
except SyntaxError:
- raise PolicyException('Syntax error in %s' % v)
+ raise PolicyException("Syntax error in %s" % v)
if not isinstance(expr_ast, ast.Expr):
- raise PolicyException(
- '%s is not an expression' % expr_ast)
+ raise PolicyException("%s is not an expression" % expr_ast)
assignment_str = """
%(verdict_var)s = (%(escape_expr)s)
- """ % {'verdict_var': verdict_var, 'escape_expr': v}
+ """ % {
+ "verdict_var": verdict_var,
+ "escape_expr": v,
+ }
assignment_ast = self.str_to_ast(assignment_str)
return assignment_ast
- elif k == 'not':
+ elif k == "not":
top_vvar = verdict_var
self.verdict_next()
sub_vvar = self.verdict_variable
block = self.gen_test(fn_template, v, sub_vvar)
assignment_str = """
%(verdict_var)s = not (%(subvar)s)
- """ % {'verdict_var': top_vvar, 'subvar': sub_vvar}
+ """ % {
+ "verdict_var": top_vvar,
+ "subvar": sub_vvar,
+ }
assignment_ast = self.str_to_ast(assignment_str)
return ast.Module(body=[block, assignment_ast])
- elif k in ['=','in']:
+ elif k in ["=", "in"]:
# This is the simplest case, we don't recurse further
# To use terms that are not simple variables, use
# the Python escape, e.g. {{ slice.creator is not None }}
@@ -512,7 +555,7 @@
try:
for t in lhs, rhs:
- py_expr = t['python']
+ py_expr = t["python"]
self.verdict_next()
vv = self.verdict_variable
@@ -520,15 +563,17 @@
try:
expr_ast = self.str_to_ast(py_expr)
except SyntaxError:
- raise PolicyException('Syntax error in %s' % v)
+ raise PolicyException("Syntax error in %s" % v)
if not isinstance(expr_ast, ast.Expr):
- raise PolicyException(
- '%s is not an expression' % expr_ast)
+ raise PolicyException("%s is not an expression" % expr_ast)
assignment_str = """
%(verdict_var)s = (%(escape_expr)s)
- """ % {'verdict_var': vv, 'escape_expr': py_expr}
+ """ % {
+ "verdict_var": vv,
+ "escape_expr": py_expr,
+ }
if t == lhs:
lhs = vv
@@ -540,14 +585,19 @@
except TypeError:
pass
- if k=='=':
- operator='=='
- elif k=='in':
- operator='in'
+ if k == "=":
+ operator = "=="
+ elif k == "in":
+ operator = "in"
comparison_str = """
%(verdict_var)s = (%(lhs)s %(operator)s %(rhs)s)
- """ % {'verdict_var': verdict_var, 'lhs': lhs, 'rhs': rhs, 'operator':operator}
+ """ % {
+ "verdict_var": verdict_var,
+ "lhs": lhs,
+ "rhs": rhs,
+ "operator": operator,
+ }
comparison_ast = self.str_to_ast(comparison_str)
combined_ast = ast.Module(body=assignments + [comparison_ast])
@@ -567,24 +617,30 @@
lblock = self.gen_test(fn_template, lhs, lvar)
rblock = self.gen_test(fn_template, rhs, rvar)
- invert = ''
- if k == '&':
- binop = 'and'
- elif k == '|':
- binop = 'or'
- elif k == '->':
- binop = 'or'
- invert = 'not'
+ invert = ""
+ if k == "&":
+ binop = "and"
+ elif k == "|":
+ binop = "or"
+ elif k == "->":
+ binop = "or"
+ invert = "not"
binop_str = """
%(verdict_var)s = %(invert)s %(lvar)s %(binop)s %(rvar)s
- """ % {'verdict_var': top_vvar, 'invert': invert, 'lvar': lvar, 'binop': binop, 'rvar': rvar}
+ """ % {
+ "verdict_var": top_vvar,
+ "invert": invert,
+ "lvar": lvar,
+ "binop": binop,
+ "rvar": rvar,
+ }
binop_ast = self.str_to_ast(binop_str)
combined_ast = ast.Module(body=[lblock, rblock, binop_ast])
return combined_ast
- elif k == 'exists':
+ elif k == "exists":
# If the variable starts with a capital letter,
# we assume that it is a model. If it starts with
# a small letter, we assume it is an enumerable
@@ -599,7 +655,11 @@
python_str = """
%(verdict_var)s = not not %(model)s.objects.filter(%(query)s)
- """ % {'verdict_var': verdict_var, 'model': var, 'query': entry}
+ """ % {
+ "verdict_var": verdict_var,
+ "model": var,
+ "query": entry,
+ }
python_ast = ast.parse(python_str)
else:
@@ -608,16 +668,20 @@
python_str = """
%(verdict_var)s = filter(lambda __elt:%(query)s, %(model)s)
- """ % {'verdict_var': verdict_var, 'model': var, 'query': entry}
+ """ % {
+ "verdict_var": verdict_var,
+ "model": var,
+ "query": entry,
+ }
python_ast = ast.parse(python_str)
return python_ast
- elif k=='forall':
+ elif k == "forall":
var, expr = v
if var.istitle():
- f = self.fol_to_python_filter(var, expr, django=True, negate = True)
+ f = self.fol_to_python_filter(var, expr, django=True, negate=True)
entry = f.pop()
self.verdict_next()
@@ -625,71 +689,95 @@
python_str = """
%(verdict_var)s = not not %(model)s.objects.filter(%(query)s)
- """ % {'verdict_var': vvar, 'model': var, 'query': entry}
+ """ % {
+ "verdict_var": vvar,
+ "model": var,
+ "query": entry,
+ }
python_ast = ast.parse(python_str)
else:
- f = self.fol_to_python_filter(var, expr, django=False, negate = True)
+ f = self.fol_to_python_filter(var, expr, django=False, negate=True)
entry = f.pop()
python_str = """
%(verdict_var)s = next(elt for elt in %(model)s if %(query)s)
- """ % {'verdict_var': vvar, 'model': var, 'query': entry}
+ """ % {
+ "verdict_var": vvar,
+ "model": var,
+ "query": entry,
+ }
python_ast = ast.parse(python_str)
negate_str = """
%(verdict_var)s = not %(vvar)s
- """ % {'verdict_var': verdict_var, 'vvar': vvar}
+ """ % {
+ "verdict_var": verdict_var,
+ "vvar": vvar,
+ }
negate_ast = ast.parse(negate_str)
return ast.Module(body=[python_ast, negate_ast])
+
def xproto_fol_to_python_test(policy, fol, model, tag=None):
if isinstance(fol, jinja2.Undefined):
- raise Exception('Could not find policy:', policy)
+ raise Exception("Could not find policy:", policy)
f2p = FOL2Python()
fol_reduced = f2p.hoist_outer(fol)
- if fol_reduced in ['True','False'] and fol != fol_reduced:
- raise TrivialPolicy("Policy %(name)s trivially reduces to %(reduced)s. If this is what you want, replace its contents with %(reduced)s"%{'name':policy, 'reduced':fol_reduced})
+ if fol_reduced in ["True", "False"] and fol != fol_reduced:
+ raise TrivialPolicy(
+ "Policy %(name)s trivially reduces to %(reduced)s. If this is what you want, replace its contents with %(reduced)s" % {
+ "name": policy,
+ "reduced": fol_reduced})
- a = f2p.gen_test_function(fol_reduced, policy, tag='security_check')
+ a = f2p.gen_test_function(fol_reduced, policy, tag="security_check")
return astunparse.unparse(a)
+
def xproto_fol_to_python_validator(policy, fol, model, message, tag=None):
if isinstance(fol, jinja2.Undefined):
- raise Exception('Could not find policy:', policy)
+ raise Exception("Could not find policy:", policy)
f2p = FOL2Python()
fol_reduced = f2p.hoist_outer(fol)
- if fol_reduced in ['True','False'] and fol != fol_reduced:
- raise TrivialPolicy("Policy %(name)s trivially reduces to %(reduced)s. If this is what you want, replace its contents with %(reduced)s"%{'name':policy, 'reduced':fol_reduced})
+ if fol_reduced in ["True", "False"] and fol != fol_reduced:
+ raise TrivialPolicy(
+ "Policy %(name)s trivially reduces to %(reduced)s. If this is what you want, replace its contents with %(reduced)s" % {
+ "name": policy,
+ "reduced": fol_reduced})
- a = f2p.gen_validation_function(fol_reduced, policy, message, tag='validator')
-
+ a = f2p.gen_validation_function(fol_reduced, policy, message, tag="validator")
+
return astunparse.unparse(a)
+
def main():
while True:
- inp = ''
+ inp = ""
while True:
inp_line = raw_input()
- if inp_line=='EOF': break
- else: inp+=inp_line
-
+ if inp_line == "EOF":
+ break
+ else:
+ inp += inp_line
+
fol_lexer = lex.lex(module=FOLLexer())
- fol_parser = yacc.yacc(module=FOLParser(), start='goal', outputdir='/tmp', debug=0)
+ fol_parser = yacc.yacc(
+ module=FOLParser(), start="goal", outputdir="/tmp", debug=0
+ )
val = fol_parser.parse(inp, lexer=fol_lexer)
- a = xproto_fol_to_python_test('pol', val, 'output', 'Test')
- #f2p = FOL2Python()
- #a = f2p.hoist_outer(val)
- print a
+ a = xproto_fol_to_python_test("pol", val, "output", "Test")
+ # f2p = FOL2Python()
+ # a = f2p.hoist_outer(val)
+ print(a)
if __name__ == "__main__":