def push_format_context(self):
"""Create a new formatting context.
The format context is used for when an explanation wants to
have a variable value formatted in the assertion message. In
this case the value required can be added using
.explanation_param(). Finally .pop_format_context() is used
to format a string of %-formatted values as added by
.explanation_param().
"""
self.explanation_specifiers = {}
self.stack.append(self.explanation_specifiers)
python类In()的实例源码
def visit_Name(self, name):
# Display the repr of the name if it's a local variable or
# _should_repr_global_name() thinks it's acceptable.
locs = ast_Call(self.builtin("locals"), [], [])
inlocs = ast.Compare(ast.Str(name.id), [ast.In()], [locs])
dorepr = self.helper("should_repr_global_name", name)
test = ast.BoolOp(ast.Or(), [inlocs, dorepr])
expr = ast.IfExp(test, self.display(name), ast.Str(name.id))
return name, self.explanation_param(expr)
def Compare_in(t, x):
if not isinstance(x.ops[0], (ast.NotIn, ast.In)):
return
if t.enable_snippets:
from ..snippets import _in, in_es6
if t.enable_es6:
t.add_snippet(in_es6)
sname = 'in_es6'
else:
t.add_snippet(_in)
sname = '_in'
result = JSCall(JSAttribute('_pj', sname), [x.left, x.comparators[0]])
if isinstance(x.ops[0], ast.NotIn):
result = JSUnaryOp(JSOpNot(), result)
return result
def syn_Compare(self, ctx, e):
left, ops, comparators = e.left, e.ops, e.comparators
for op in ops:
if not isinstance(op, (ast.Eq, ast.NotEq, ast.Is, ast.IsNot, ast.In, ast.NotIn)):
raise _errors.TyError("Invalid comparison operator on strings.", e)
for e_ in _util.tpl_cons(left, comparators):
if hasattr(e_, 'match'):
continue # already synthesized
ctx.ana(e_, self)
return _boolean.boolean
def syn_Compare(self, ctx, e):
left, ops, comparators = e.left, e.ops, e.comparators
for op in ops:
if isinstance(op, (ast.In, ast.NotIn)):
raise _errors.TyError("Type num does not support this operator.", op)
for e_ in _util.tpl_cons(left, comparators):
if hasattr(e_, 'match'):
continue # already synthesized
ctx.ana(e_, self)
return _boolean.boolean
def syn_Compare(self, ctx, e):
left, ops, comparators = e.left, e.ops, e.comparators
for op in ops:
if isinstance(op, (ast.In, ast.NotIn)):
raise _errors.TyError("Type ieee does not support this operator.", op)
for e_ in _util.tpl_cons(left, comparators):
if hasattr(e_, 'match'):
continue # already synthesized
ctx.ana(e_, self)
return _boolean.boolean
def syn_Compare(self, ctx, e):
left, ops, comparators = e.left, e.ops, e.comparators
for op in ops:
if isinstance(op, (ast.Lt, ast.LtE, ast.Gt, ast.GtE)):
raise _errors.TyError("No ordering relation on complex numbers.", e)
elif isinstance(op, (ast.In, ast.NotIn)):
raise _errors.TyError("Type complex does not support this operator.", op)
for e_ in _util.tpl_cons(left, comparators):
if hasattr(e_, 'match'):
continue # already synthesized
ctx.ana(e_, self)
return _boolean.boolean
def areDisjoint(a, b):
"""Are the sets of values that satisfy these two boolean constraints disjoint?"""
# The easiest way to be disjoint is to have comparisons that cover different areas
if type(a) == type(b) == ast.Compare:
aop = a.ops[0]
bop = b.ops[0]
aLeft = a.left
aRight = a.comparators[0]
bLeft = b.left
bRight = b.comparators[0]
alblComp = compareASTs(aLeft, bLeft, checkEquality=True)
albrComp = compareASTs(aLeft, bRight, checkEquality=True)
arblComp = compareASTs(aRight, bLeft, checkEquality=True)
arbrComp = compareASTs(aRight, bRight, checkEquality=True)
altype = type(aLeft) in [ast.Num, ast.Str]
artype = type(aRight) in [ast.Num, ast.Str]
bltype = type(bLeft) in [ast.Num, ast.Str]
brtype = type(bRight) in [ast.Num, ast.Str]
if (type(aop) == ast.Eq and type(bop) == ast.NotEq) or \
(type(bop) == ast.Eq and type(aop) == ast.NotEq):
# x == y, x != y
if (alblComp == 0 and arbrComp == 0) or (albrComp == 0 and arblComp == 0):
return True
elif type(aop) == type(bop) == ast.Eq:
if (alblComp == 0 and arbrComp == 0) or (albrComp == 0 and arblComp == 0):
return False
# x = num1, x = num2
elif alblComp == 0 and artype and brtype:
return True
elif albrComp == 0 and artype and bltype:
return True
elif arblComp == 0 and altype and brtype:
return True
elif arbrComp == 0 and altype and bltype:
return True
elif (type(aop) == ast.Lt and type(bop) == ast.GtE) or \
(type(aop) == ast.Gt and type(bop) == ast.LtE) or \
(type(aop) == ast.LtE and type(bop) == ast.Gt) or \
(type(aop) == ast.GtE and type(bop) == ast.Lt) or \
(type(aop) == ast.Is and type(bop) == ast.IsNot) or \
(type(aop) == ast.IsNot and type(bop) == ast.Is) or \
(type(aop) == ast.In and type(bop) == ast.NotIn) or \
(type(aop) == ast.NotIn and type(bop) == ast.In):
if alblComp == 0 and arbrComp == 0:
return True
elif (type(aop) == ast.Lt and type(bop) == ast.LtE) or \
(type(aop) == ast.Gt and type(bop) == ast.GtE) or \
(type(aop) == ast.LtE and type(bop) == ast.Lt) or \
(type(aop) == ast.GtE and type(bop) == ast.Gt):
if albrComp == 0 and arblComp == 0:
return True
elif type(a) == type(b) == ast.BoolOp:
return False # for now- TODO: when is this not true?
elif type(a) == ast.UnaryOp and type(a.op) == ast.Not:
if compareASTs(a.operand, b, checkEquality=True) == 0:
return True
elif type(b) == ast.UnaryOp and type(b.op) == ast.Not:
if compareASTs(b.operand, a, checkEquality=True) == 0:
return True
return False
def negate(op):
"""Return the negation of the provided operator"""
if op == None:
return None
top = type(op)
neg = not op.negated if hasattr(op, "negated") else True
if top == ast.And:
newOp = ast.Or()
elif top == ast.Or:
newOp = ast.And()
elif top == ast.Eq:
newOp = ast.NotEq()
elif top == ast.NotEq:
newOp = ast.Eq()
elif top == ast.Lt:
newOp = ast.GtE()
elif top == ast.GtE:
newOp = ast.Lt()
elif top == ast.Gt:
newOp = ast.LtE()
elif top == ast.LtE:
newOp = ast.Gt()
elif top == ast.Is:
newOp = ast.IsNot()
elif top == ast.IsNot:
newOp = ast.Is()
elif top == ast.In:
newOp = ast.NotIn()
elif top == ast.NotIn:
newOp = ast.In()
elif top == ast.NameConstant and op.value in [True, False]:
op.value = not op.value
op.negated = neg
return op
elif top == ast.Compare:
if len(op.ops) == 1:
op.ops[0] = negate(op.ops[0])
op.negated = neg
return op
else:
values = []
allOperands = [op.left] + op.comparators
for i in range(len(op.ops)):
values.append(ast.Compare(allOperands[i], [negate(op.ops[i])],
[allOperands[i+1]], multiCompPart=True))
newOp = ast.BoolOp(ast.Or(multiCompOp=True), values, multiComp=True)
elif top == ast.UnaryOp and type(op.op) == ast.Not and \
eventualType(op.operand) == bool: # this can mess things up type-wise
return op.operand
else:
# this is a normal value, so put a not around it
newOp = ast.UnaryOp(ast.Not(addedNot=True), op)
transferMetaData(op, newOp)
newOp.negated = neg
return newOp
def _translate_compare(self, left, ops, comparators, location):
if isinstance(ops[0], ast.In) or isinstance(ops[0], ast.NotIn):
if len(comparators) != 1:
raise translation_error('only <element> [not] in <sequence> supported',
location, self.lines[location[0]],
suggestion='2 in [2] in [[2]] is cute, but it\'s not supported')
else:
in_node = self._translate_in(left, comparators[0], location)
if isinstance(ops[0], ast.In):
return in_node
else:
return {'type': 'unary_op', 'op': 'not', 'value': in_node, 'pseudo_type': 'Boolean'}
op = PSEUDO_OPS[type(ops[0])]
right_node = self._translate_node(comparators[0])
left_node = self._translate_node(left)
self._confirm_comparable(op, left_node['pseudo_type'], right_node['pseudo_type'], location)
result = {
'type': 'comparison',
'op': op,
'left': left_node,
'right': right_node,
'pseudo_type': 'Boolean'
}
if len(comparators) == 1:
return result
else:
for r in comparators[1:]:
left_node, right_node = right_node, self._translate_node(r)
self._confirm_comparable(op, left_node['pseudo_type'], right_node['pseudo_type'], location)
result = {
'type': 'binary_op',
'op': 'and',
'left': result,
'right': {
'type': 'comparison',
'op': op,
'left': left_node,
'right': right_node,
'pseudo_type': 'Boolean'
},
'pseudo_type': 'Boolean'
}
return result
def _visit_compare(self, left, op, right):
swap = False
if not isinstance(left, ast.Attribute):
left, right = right, left
swap = True
if not isinstance(left, ast.Attribute):
return
hardcoded_errno = (
left.attr == 'errno' and
op in astaux.equality_ops and
isinstance(right, ast.Num) and
isinstance(right.n, int) and
right.n in errno_constants
)
if hardcoded_errno:
yield self.tag(right, '*hardcoded-errno-value', right.n)
sys_attr_comparison = (
isinstance(left.value, ast.Name) and
left.value.id == 'sys'
)
if sys_attr_comparison:
if left.attr == 'version':
tpl = None
if isinstance(right, ast.Str):
if op in astaux.inequality_ops:
try:
tpl = sysversion.version_to_tuple(right.s)
except (TypeError, ValueError):
pass
elif swap and (op in astaux.in_ops):
if right.s == 'PyPy':
tpl = False
op = ast.Eq if isinstance(op, ast.In) else ast.NotEq
yield self.tag(left, 'sys.version-comparison',
format_cmp('platform.python_implementation()', op, repr('PyPy'))
)
if tpl is False:
pass
elif tpl is None:
yield self.tag(left, 'sys.version-comparison')
else:
yield self.tag(left, 'sys.version-comparison',
format_cmp('sys.version_info', op, tpl, swap=swap)
)
elif left.attr == 'hexversion':
tpl = None
if isinstance(right, ast.Num) and (op in astaux.numeric_cmp_ops):
try:
tpl = sysversion.hexversion_to_tuple(right.n)
except (TypeError, ValueError):
pass
if tpl is None:
yield self.tag(left, 'sys.hexversion-comparison')
else:
yield self.tag(left, 'sys.hexversion-comparison',
format_cmp('sys.version_info', op, tpl, swap=swap)
)