Why do divisions not work in jsonpath-ng? - python

Jsonpath-ng offers basic arithmetic as in:
from jsonpath_ng import jsonpath
from jsonpath_ng.ext import parse
jsonpath_expr = parse('$.foo * 2')
target = {'foo': 2}
result = jsonpath_expr.find(target)
result = [match.value for match in result]
print(result)
result: [4]
However, if I change the expression to $.foo / 2, then I get a Parse Error:
Traceback (most recent call last):
File "test.py", line 4, in <module>
jsonpath_expr = parse('$.foo / 2')
File "C:\Users\micha\AppData\Roaming\Python\Python38\site-packages\jsonpath_ng\ext\parser.py", line 172, in parse
return ExtentedJsonPathParser(debug=debug).parse(path)
File "C:\Users\micha\AppData\Roaming\Python\Python38\site-packages\jsonpath_ng\parser.py", line 32, in parse
return self.parse_token_stream(lexer.tokenize(string))
File "C:\Users\micha\AppData\Roaming\Python\Python38\site-packages\jsonpath_ng\parser.py", line 55, in parse_token_stream
return new_parser.parse(lexer = IteratorToTokenStream(token_iterator))
File "C:\Users\micha\AppData\Roaming\Python\Python38\site-packages\ply\yacc.py", line 333, in parse
return self.parseopt_notrack(input, lexer, debug, tracking, tokenfunc)
File "C:\Users\micha\AppData\Roaming\Python\Python38\site-packages\ply\yacc.py", line 1201, in parseopt_notrack
tok = call_errorfunc(self.errorfunc, errtoken, self)
File "C:\Users\micha\AppData\Roaming\Python\Python38\site-packages\ply\yacc.py", line 192, in call_errorfunc
r = errorfunc(token)
File "C:\Users\micha\AppData\Roaming\Python\Python38\site-packages\jsonpath_ng\parser.py", line 69, in p_error
raise Exception('Parse error at %s:%s near token %s (%s)' % (t.lineno, t.col, t.value, t.type))
Exception: Parse error at 1:6 near token / (SORT_DIRECTION)
I can sometimes work around this issue by dividing by the inverse value, so I would do $.foo * 0.5 to get the result [1.0]. But this doesn't work if both sides of the equation are numeric values of different types (int or float). So 2 * 0.5 and 0.5 * 2 will result in a Parse error, but 2.0 * 0.5 will not.
How do I get divisions to work? And why can I not multiply a float by an integer?

Those are both grammar bugs.
Extended JSON paths are allowed to be suffixed with a bracketed expression containing a list of "sorts"; each sort starts with / or \. To make that work, the extended lexer recognises those two symbols as the token SORT_DIRECTION, which takes precedence over the recognition of / as an arithmetic operator. Consequently the use of / as an arithmetic operator is not allowed by the parser. (In fact, the problem goes deeper than that, but that's the essence.)
For some reason, the grammar author chose to separate NUMBER (actually, integer) and FLOAT in arithmetic expressions, which means that they had to enumerate the possible combinations. What they chose was:
jsonpath : NUMBER operator NUMBER
| FLOAT operator FLOAT
| ID operator ID
| NUMBER operator jsonpath
| FLOAT operator jsonpath
| jsonpath operator NUMBER
| jsonpath operator FLOAT
| jsonpath operator jsonpath
There are other problems with this grammar, but the essence here is that it permits NUMBER operator NUMBER and FLOAT operator FLOAT but does not permit NUMBER operator FLOAT or FLOAT operator NUMBER, which is what you observe. However, path expressions can work with either NUMBER or FLOAT.

Related

Add binary operator to z3

I'm trying to parse and translate a string to its equivalent z3 form.
import z3
expr = 'x + y = 10'
p = my_parse_expr_to_z3(expr) # results in: ([x, '+', y], '==', [10])
p = my_flatten(p) # after flatten: [x, '+', y, '==', 10]
Type-checking of parsed string:
for e in p:
print(type(e), e)
# -->
<class 'z3.z3.ArithRef'> x
<class 'str'> +
<class 'z3.z3.ArithRef'> y
<class 'str'> ==
<class 'int'> 10
When I now try:
s = z3.Solver()
s.add(*p)
I get:
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "...\venv\lib\site-packages\z3\z3.py", line 6938, in add
self.assert_exprs(*args)
File "..\venv\lib\site-packages\z3\z3.py", line 6926, in assert_exprs
arg = s.cast(arg)
File "..\venv\lib\site-packages\z3\z3.py", line 1505, in cast
_z3_assert(self.eq(val.sort()), "Value cannot be converted into a Z3 Boolean value")
File "..\venv\lib\site-packages\z3\z3.py", line 112, in _z3_assert
raise Z3Exception(msg)
z3.z3types.Z3Exception: Value cannot be converted into a Z3 Boolean value
The equal and plus signs occurs to be of the false type/usage? How can I translate that correctly?
Where's the definition of parse_expr_to_z3 coming from? It's definitely not something that comes with z3 itself, so you must be getting it from some other third-party, or perhaps you wrote it yourself. Without knowing how it's defined, it's impossible for anyone on stack-overflow to give you any guidance.
In any case, as you suspected its results are not something you can feed back to z3. It fails precisely because what you can add to the solver must be constraints, i.e., expressions of type Bool in z3. Clearly, none of those constituents have that type.
So, long story short, this parse_expr_to_z3 doesn't seem to be designed to do what you intended. Contact its developer for further details on what the intended use case is.
If you're trying to load assertions from a string to z3, then you can do that using the so called SMTLib format. Something like:
from z3 import *
expr = """
(declare-const x Int)
(declare-const y Int)
(assert (= (+ x y) 10))
"""
p = parse_smt2_string(expr)
s = Solver()
s.add(p)
print(s.check())
print(s.model())
This prints:
sat
[y = 0, x = 10]
You can find more about SMTLib syntax in https://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2021-05-12.pdf
Note that trying to do this using any other syntax (like your proposed 'x + y = 10') is going to require knowledge of the variables in the string (x and y in this case, but can of course be arbitrary), and what sort of symbols (+ and = in your case, but again can be any number of different symbols) and their precise meanings. Without knowing your exact needs, it's hard to opine, but using anything other than the existing support for SMTLib syntax itself will require a non-insignificant amount of work.

Z3python XOR sum?

I'm currently trying to solve some equation with z3python, and I am coming across a situation I could not deal with.
I need to xor certain BitVecs with specific non ascii char values, and sum them up to check a checksum.
Here is an example :
pbInput = [BitVec("{}".format(i), 8) for i in range(KEY_LEN)]
password = "\xff\xff\xde\x8e\xae"
solver.add(Xor(pbInput[0], password[0]) + Xor(pbInput[3], password[3]) == 300)
It results in a z3 type exception :
z3.z3types.Z3Exception: Value cannot be converted into a Z3 Boolean value.
I found this post and tried to apply a function to my password string, adding this line to my script :
password = Function(password, StringSort(), IntSort(), BitVecSort(8))
But of course it fails as the string isn't an ASCII string.
I don't care about it being a string, I tried to just do Xor(pbInput[x] ^ 0xff), but this doesn't work either. I could not find any documentation on this particular situation.
EDIT :
Here is the full traceback.
Traceback (most recent call last):
File "solve.py", line 18, in <module>
(Xor(pbInput[0], password[0])
File "/usr/local/lib/python2.7/dist-packages/z3/z3.py", line 1555, in Xor
a = s.cast(a)
File "/usr/local/lib/python2.7/dist-packages/z3/z3.py", line 1310, in cast
_z3_assert(self.eq(val.sort()), "Value cannot be converted into a Z3 Boolean value")
File "/usr/local/lib/python2.7/dist-packages/z3/z3.py", line 91, in _z3_assert
raise Z3Exception(msg)
z3.z3types.Z3Exception: Value cannot be converted into a Z3 Boolean value
Thanks in advance if you have any idea about how I could do this operation!
There are two problems in your code.
Xor is for Bool values only; for bit-vectors simply use ^
Use the function ord to convert characters to integers before passing to xor
You didn't give your full program (which is always helpful!), but here's how you'd write that section in z3py as a full program:
from z3 import *
solver = Solver()
KEY_LEN = 10
pbInput = [BitVec("c_{}".format(i), 8) for i in range(KEY_LEN)]
password = "\xff\xff\xde\x8e\xae"
solver.add((pbInput[0] ^ ord(password[0])) + (pbInput[3] ^ ord(password[3])) == 300)
print solver.check()
print solver.model()
This prints:
sat
[c_3 = 0, c_0 = 97]
(I gave the variables better names to distinguish more properly.) So, it's telling us the solution is:
>>> (0xff ^ 97) + (0x8e ^ 0)
300
Which is indeed what you asked for.

Convert a sympy poly with imaginary powers to an mpmath mpc

I have a sympy poly that looks like:
Poly(0.764635937801645*I**4 + 7.14650839258644*I**3 - 0.667712176660315*I**2 - 2.81663805543677*I - 0.623299856233272, I, domain='RR')
I'm converting to mpc using the following code:
a = val.subs('I',1.0j)
b = sy.re(a)
c = sy.im(a)
d = mpmath.mpc(b,c)
Two questions.
Assuming my mpc and sympy type have equal precision (of eg 100 dps) is there a precision loss using this conversion from a to d?
Is there a better way to convert?
Aside: sympy seems to treat I just like a symbol here. How do I get sympy to simplify this polynomial?
Edit: Ive also noticed that the following works in place of a above:
a = val.args[0]
Strings and expressions
Root cause of the issue is seen in val.subs('I', 1.0j) -- you appear to pass strings as arguments to SymPy functions. There are some valid uses for this (such as creation of high-precision floats), but when symbols are concerned, using strings is a recipe for confusion. The string 'I' gets implicitly converted to SymPy expression Symbol('I'), which is different from SymPy expression I. So the answer to
How do I get sympy to simplify this polynomial?
is to revisit the process of creation of that polynomial, and fix that. If you really need to create it from a string, then use locals parameter:
>>> S('3.3*I**2 + 2*I', locals={'I': I})
-3.3 + 2*I
Polynomials and expressions
If the Poly structure is not needed, use the method as_expr() of Poly to get an expression from it.
Conversion to mpmath and precision loss
is there a precision loss using this conversion from a to d?
Yes, splitting into real and imaginary and then recombining can lead to precision loss. Pass a SymPy object directly to mpc if you know it's a complex number. Or to mpmathify if you want mpmath to decide what type it should have. An example:
>>> val = S('1.111111111111111111111111111111111111111111111111')*I**3 - 2
>>> val
-2 - 1.111111111111111111111111111111111111111111111111*I
>>> import mpmath
>>> mpmath.mp.dps = 40
>>> mpmath.mpc(val)
mpc(real='-2.0', imag='-1.111111111111111111111111111111111111111111')
>>> mpmath.mpmathify(val)
mpc(real='-2.0', imag='-1.111111111111111111111111111111111111111111')
>>> mpmath.mpc(re(val), im(val))
mpc(real='-2.0', imag='-1.111111111111111111111111111111111111111114')
Observations:
When I is actual imaginary unit, I**3 evaluates fo -I, you don't have to do anything for it to happen.
A string representation of high-precision decimal is used to create such a float in SymPy. Here S stands for sympify. One can also be more direct and use Float('1.1111111111111111111111111')
Direct conversion of a SymPy complex number to an mpmath complex number is preferable to splitting in real/complex and recombining.
Conclusion
Most of the above is just talking around an XY problem. Your expression with I was not what you think it was, so you tried to do strange things that were not needed, and my answer is mostly a waste of time.
I'm adding my own answer here, as FTP's answer, although relevant and very helpful, did not (directly) resolve my issue (which wasn't that clear from the question tbh). When I ran the code in his example I got the following:
>>> from sympy import *
>>> import mpmath
>>> val = S('1.111111111111111111111111111111111111111111111111')*I**3 - 2
>>> val
-2 - 1.111111111111111111111111111111111111111111111111*I
>>> mpmath.mp.dps = 40
>>> mpmath.mpc(val)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\site-packages\mpmath\ctx_mp_python.py", line 373, in __new__
real = cls.context.mpf(real)
File "C:\Python27\lib\site-packages\mpmath\ctx_mp_python.py", line 77, in __new__
v._mpf_ = mpf_pos(cls.mpf_convert_arg(val, prec, rounding), prec, rounding)
File "C:\Python27\lib\site-packages\mpmath\ctx_mp_python.py", line 96, in mpf_convert_arg
raise TypeError("cannot create mpf from " + repr(x))
TypeError: cannot create mpf from -2 - 1.111111111111111111111111111111111111111111111111*I
>>> mpmath.mpmathify(val)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\site-packages\mpmath\ctx_mp_python.py", line 662, in convert
return ctx._convert_fallback(x, strings)
File "C:\Python27\lib\site-packages\mpmath\ctx_mp.py", line 614, in _convert_fallback
raise TypeError("cannot create mpf from " + repr(x))
TypeError: cannot create mpf from -2 - 1.111111111111111111111111111111111111111111111111*I
>>> mpmath.mpc(re(val), im(val))
mpc(real='-2.0', imag='-1.111111111111111111111111111111111111111114')
>>> mpmath.mpmathify(val)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\site-packages\mpmath\ctx_mp_python.py", line 662, in convert
return ctx._convert_fallback(x, strings)
File "C:\Python27\lib\site-packages\mpmath\ctx_mp.py", line 614, in _convert_fallback
raise TypeError("cannot create mpf from " + repr(x))
TypeError: cannot create mpf from -2 - 1.111111111111111111111111111111111111111111111111*I
Updating my sympy (1.0->1.1.1) and mpmath (0.19->1.0.0) fixed the exceptions. I did not test which of these upgrades actually resolved the issue.

Getting type error:can't multiply sequence by non-int of type 'function'

I keep getting this error:
Traceback (most recent call last):
File "C:\Users\Andrew\Desktop\lab10.py", line 66, in <module>
main()
File "C:\Users\Andrew\Desktop\lab10.py", line 55, in main
volumeRectangle=VR(length,width,height)
File "C:\Users\Andrew\Desktop\lab10.py", line 20, in VR
volume=length*width*height
TypeError: can't multiply sequence by non-int of type 'function'
Code
import math
def AC(radius):
area = math.pi * radius ** 2
return area
def AR(length,width):
area=length*width
return area
def VC(radius,height):
volume=math.pi*radius*radius*height
return volume
def VR(length,width,height):
volume=length*width*height
return volume
# WRITE ALL THE OTHER FUNCTIONS
def main():
inFile = open("lab10.input","r")
# get calculation type, but wait on dimension(s)
type = (inFile.readline()).strip()
while (type != "###"):
if (type == "AC"):
radius = eval(inFile.readline())
circleArea = AC(radius)
print(format("Area of a Circle","30s"),format(circleArea,"15.2f"))
if (type=='AR'):
length=eval(inFile.readline())
width=eval(inFile.readline())
rsArea=ARR(length,width)
print(format("Area of a Rectangle or Square",'30s'),format(rsArea,'15.2f'))
if (type=='VC'):
radius=eval(inFile.readline())
height=eval(inFile.readline())
volumeCylinder=VC(radius,height)
print(format("Volume of a Cylinder",'30s'),format(volumeCylinder,'15.2f'))
if (type=='VR'):
length=eval(inFile.readline())
width=eval(inFile.readline())
height=eval(inFile.readline())
volumeRectangle=VR(length,width,height)
print(format("Volume of a Rectangle",'30s'),format(volumeRectangle,'15.2f'))
# do the processing for all other types of calculations
# get calculation type, but wait on dimension(s)
type = (inFile.readline()).strip()
main()
This is what the input file looks like. INPUT FILE
AC
7.5
SAC
4
VR
2, 3, 4.1
AR
13, 3.25
SAS
24
###
0
This seem to work. Like Paul said inputs in the same lines were getting messed up.
while (type != "###"):
if (type == "AC"):
radius = eval(inFile.readline())
circleArea = AC(radius)
print(format("Area of a Circle","30s"),format(circleArea,"15.2f"))
if (type=='AR'):
length, width=eval(inFile.readline().strip())
rsArea=AR(length,width)
print(format("Area of a Rectangle or Square",'30s'),format(rsArea,'15.2f'))
if (type=='VC'):
radius, height=eval(inFile.readline().strip())
volumeCylinder=VC(radius,height)
print(format("Volume of a Cylinder",'30s'),format(volumeCylinder,'15.2f'))
if (type=='VR'):
length, width, height =eval(inFile.readline().strip())
volumeRectangle=VR(length,width,height)
print(format("Volume of a Rectangle",'30s'),format(volumeRectangle,'15.2f'))
You are running into issues when you hit the VR command. This is because it has multiple input parameters. You 'got away with it' in the first command (AC) as it has only a single parameter and eval turned it into a single float value.
For VR there are 3 parameters and you are trying to set each of these parameters by reading a line in the file (that's 3 lines read). Now all your parameters are actually together on single line. So if you thought you were reading the parameters
12, 3, 4.1
You are not you are reading
2, 3, 4.1
AR
13, 3.25
When you eval these you get tuples for the 1st and 3rd lines and since AR is a function you defined, eval('AR') returns you that function (which makes sense of the exception error message you received). This is one of the hazards of using eval, it can lead to unexpected results.
So your VR call looks like
VR((2, 3, 4.1), AR, (13, 3.25))
Which is doubtless not what you expected.
Two ways you could resolve it. I've abbreviated your code for clarity. You'd obviously need to replicate in the other commands.
Stick with the tuples and ast.literal_eval (use that instead of eval).
import math
from ast import literal_eval
def VR(length,width,height):
return length * width * height
def main():
with open("lab10.input","r") as inFile:
acttype = (inFile.readline()).strip()
while (acttype != "###"):
if (acttype=='VR'):
params = literal_eval(inFile.readline())
volumeRectangle = VR(*params)
print(format("Volume of a Rectangle",'30s'),format(volumeRectangle,'15.2f'))
acttype = (inFile.readline()).strip()
main()
or avoid the eval by splitting the line on ,.
import math
def VR(length,width,height):
return length * width * height
def main():
with open("lab10.input","r") as inFile:
acttype = (inFile.readline()).strip()
while (acttype != "###"):
if (acttype=='VR'):
params = map(float, inFile.readline().split(','))
volumeRectangle = VR(*params)
print(format("Volume of a Rectangle",'30s'),format(volumeRectangle,'15.2f'))
acttype = (inFile.readline()).strip()
main()

Python Operation % not working?

I cant seem to get this working, cant someone point me in the right direction? If i put the the values without promting it works buut when i do this i get error.
username1 = raw_input('Enter Username:\n')
password = raw_input('Enter Password:\n')
r = requests.get("https://linktoasp.net/",auth=HttpNtlmAuth("domain\\%s",password),cookies=jar) % (username1)
Error:
Traceback (most recent call last): File "attend_punch.py", line 32,
in
r = requests.get("https://linktoasp.netserver/homeportal/default.aspx",auth=HttpNtlmAuth("domain\\%r",password),cookies=jar)
% (username1) TypeError: unsupported operand type(s) for %:
'Response' and 'str'
You could try this instead
auth = HttpNtlmAuth("domain\\%s" % username1, password), cookies = jar)
What you probably want is:
r = requests.get(
"https://linktoasp.net/",
auth=HttpNtlmAuth("domain\\%s" % username1,password),cookies=jar)
In order to do string interpolation with %, the % and the value need to immediately follow the string:
"domain\\%s" % username1
rather than just coming later in the line:
HttpNtlmAuth("domain\\%s", ...) % username1
The % symbol can have 2 meanings in Python:
The modulo operator which will give you the remainder of the division of an int by the other. That is usually used for 2 numbers.
The string formatting operator which comes after a string to replace the placeholders with actual values. That's what you want, but you are not placing it right after the string, so Python interprets it as the modulo operator, and since it's not defined for any object (only for int usually), raises that exception.

Categories