-
-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Python3 #13
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello,
I agree with most of the changes. In particular, the Cython macros look ok to me; I have no better idea anyway.
Ccan you please just address the 4 comments I made?
cypari2/closure.pyx
Outdated
Examples: | ||
|
||
>>> from cypari2.closure import objtoclosure | ||
>>> def pymul(i,j): return i*j |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change? I think that was meant explicitly to test lambdas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lambda functions behavior are different between Python2 and Python3. In Python3, a lambda function has only one argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?? What do you mean? I'm using Python 3.6, and I see no problem with the old test
>>> objtoclosure(lambda i,j: i*j)
(v1,v2,v3,v4,v5)->call_python(v1,v2,v3,v4,v5,140180350752424)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. I do not know what happend in the first place. This is back with 418cf40
.
cypari2/convert.pyx
Outdated
5 | ||
>>> gen_to_integer(pari("Pol(42)")) | ||
42 | ||
>>> gen_to_integer(pari("u")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, did you get to the bottom of this? Why was it failing on Travis?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No idea. This is still failing on travis. However the option IGNORE_EXCEPTION_DETAIL
in doctests make this failure disappear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may at least want to open an issue for this, or we may forget about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cypari2/convert.pyx
Outdated
@@ -589,7 +615,7 @@ cpdef gen_to_python(Gen z): | |||
elif t == t_VEC or t == t_COL: | |||
return [gen_to_python(x) for x in z.python_list()] | |||
elif t == t_VECSMALL: | |||
return z.python_list_small() | |||
return z.python_list_small() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This diff is weird!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed! Fixed by d7b7a3e
cypari2/pari_instance.pyx
Outdated
|
||
EXAMPLES:: | ||
|
||
sage: pari.debugstack() # random |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't there a way to leave the example undoctested?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No without a hook to doctest. This is what they did in cypari and what we might want to do... (they also have a hook for 32 vs 64 bits doctests)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All right, we can think about this later.
It's wrong to assume that every string coming from PARI is ASCII. I mean, people should be able to write PARI/GP code like I also don't agree with changing |
This is also wrong, because you aren't calling
This should be something like
|
Changes
Travis looks happy. |
ping! |
I don't think it is good style to hard-code the Python version number in the |
Some more docs for If so, it seems more reasonable to have Also: what is acceptable input for |
@jdemeyer concerning your harceded version, what is the point? and what are you referring to exactly? Note that only the major version (2 or 3) is taken into account. And a Python2 compiled version will not be Python3 compatible. And what is happening is during cythonization, it is not hardcoded in the compiled version. |
You make the assumption that the version of Python which is used by Cython equals the version of Python which will use cypari2. There is no need to make that assumption. Not making this assumption could allow to install cypari2 on systems which do not have Cython installed. |
Agreed. But the target Python version has to be known at compilation time anyway (e.g.
Then you would need two versions of the C files. One Python2 compatible and one Python3 compatible. I don't think this point is relevant to the current PR. |
That's for Cython to decide, not for us. If you write Cython tries hard to output |
Funny cython behavior... with
I got with python2
and with Python3
|
Let me repeat that it is not hardcoded anywhere. There is a constant Cython macro that enables/disables some portion of the code... and it is trivial to make it configurable. |
sadly network in Bordeaux is down... so Travis is not happy. |
network back, Travis happy! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no more comments about the general approach, but several minor remarks, see review.
cypari2/convert.pyx
Outdated
>>> gen_to_integer(pari("1 - 2^64")) == -18446744073709551615 | ||
True | ||
>>> import sys | ||
>>> if sys.version_info.major == 2: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same test should be done with int
instead of long
(and you might as well do it on Python 2 and Python 3).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see 5b66460
cypari2/convert.pyx
Outdated
@@ -525,21 +535,21 @@ cpdef gen_to_python(Gen z): | |||
[1, 2, 3] | |||
>>> type(a1) | |||
<... 'list'> | |||
>>> map(type, a1) | |||
>>> list(map(type, a1)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is ugly. Write [type(x) for x in a1]
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see 3040e65
cypari2/convert.pyx
Outdated
[<... 'int'>, <... 'int'>, <... 'int'>] | ||
|
||
>>> a2 = gen_to_python(z2); a2 | ||
[1, 3.4, [-5, 2], inf] | ||
>>> type(a2) | ||
<... 'list'> | ||
>>> map(type, a2) | ||
>>> list(map(type, a2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Idem
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also 3040e65
cypari2/convert.pyx
Outdated
[<... 'int'>, <... 'float'>, <... 'list'>, <... 'float'>] | ||
|
||
>>> a3 = gen_to_python(z3); a3 | ||
[1, 5.2] | ||
>>> type(a3) | ||
<... 'list'> | ||
>>> map(type, a3) | ||
>>> list(map(type, a3)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Idem
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also 3040e65
cypari2/convert.pyx
Outdated
@@ -607,6 +617,6 @@ cpdef gen_to_python(Gen z): | |||
else: | |||
return -INFINITY | |||
elif t == t_STR: | |||
return str(z) | |||
return to_string(<bytes> GSTR(g)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the <bytes>
really needed here? (I haven't checked, maybe it is)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is indeed not needed (see 92f558b)
@@ -38,6 +38,9 @@ AUTHORS: | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that you rely on explicit conversions in many other places, I think it's better to be explicit everywhere. This means dropping cython: c_string_encoding=default
and adding to_string
or to_bytes
where needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see b5e5375
>>> long(pari("Mod(2, 7)")) | ||
2L | ||
>>> if sys.version_info.major == 3: | ||
... long = int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
cypari2/gen.pyx
Outdated
vstr = kwds.keys() # Variables as Python strings | ||
t0 = objtogen(kwds.values()) # Replacements | ||
vstr = list(kwds.keys()) # Variables as Python strings | ||
t0 = objtogen(list(kwds.values())) # Replacements |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
list()
should not be needed here: objtogen
can deal with generators.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see fa24efb
cypari2/pari_instance.pyx
Outdated
cdef char s[2] | ||
s[0] = c | ||
s[1] = 0 | ||
sys.stdout.write(s) | ||
sys.stdout.write(to_string(<bytes> s)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like this since you are converting bytes
to str
which sys.stdout
immediately needs to convert back to bytes
. In Python 3, you can use sys.stdout.buffer
for the underlying stream which accepts bytes
. So you could do something like:
try:
stdout_bytes = sys.stdout.bytes
except AttributeError:
stdout_bytes = sys.stdout
stdout_bytes.write(s)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does not work as is since sys.stdout is sometimes redirected (e.g. doctest). I used
try:
sys.stdout.buffer.write(s)
except AttributeError:
sys.stdout.write(to_string(s))
See b4410fc
|
||
print("="*80) | ||
print("Testing {}".format(mod.__name__)) | ||
test = doctest.testmod(mod, optionflags=doctest.ELLIPSIS|doctest.REPORT_NDIFF) | ||
test = doctest.testmod(mod, optionflags=doctest.ELLIPSIS|doctest.REPORT_NDIFF|doctest.IGNORE_EXCEPTION_DETAIL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this still needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is. In Python3, pari error are printed
Traceback (most recent call last):
...
cypari2.handle_error.PariError: MSG
while in Python2 it is
Traceback (most recent call last):
...
PariError: MSG
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few more comments, all easy to fix.
# avoid string conversion if possible | ||
sys.stdout.buffer.write(s) | ||
except AttributeError: | ||
sys.stdout.write(to_string(s)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need to_string()
here. The whole point is that you want to write bytes
without conversion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes you do. It is perfectly valid to redirect sys.stdout
to some other streams that might not support the buffer thing (like the doctest module does). In other words the except
is not only intended for Python2. In particular the to_string
is mandatory in Python3 (and useless in Python2). Note that to_string
does not perform any conversion in Python2.
# avoid string conversion if possible | ||
sys.stdout.buffer.write(s) | ||
except AttributeError: | ||
sys.stdout.write(to_string(s)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need to_string()
here. The whole point is that you want to write bytes
without conversion.
cypari2/gen.pyx
Outdated
@@ -4182,14 +4193,14 @@ cdef class Gen(Gen_auto): | |||
return new_gen(gsubst(self.g, varn(self.g), t0.g)) | |||
|
|||
# Call substvec() using **kwds | |||
vstr = kwds.keys() # Variables as Python strings | |||
t0 = objtogen(kwds.values()) # Replacements | |||
vstr = iter(kwds.keys()) # Variables as Python strings |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be kwds.iterkeys()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
iterkeys
does not exist in Python3: kwds.keys()
is already an iterator.
cypari2/string_utils.pyx
Outdated
|
||
import sys | ||
encoding = sys.getfilesystemencoding() | ||
cdef int PY_MAJOR_VERSION = sys.version_info.major |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be more efficient to make this a compile-time constant with
cdef extern from *:
int PY_MAJOR_VERSION
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in d9efdf8
else: | ||
raise TypeError | ||
|
||
cpdef unicode to_unicode(s): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe cpdef inline
for efficiency.
cypari2/string_utils.pyx
Outdated
encoding = sys.getfilesystemencoding() | ||
cdef int PY_MAJOR_VERSION = sys.version_info.major | ||
|
||
cpdef bytes to_bytes(s): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe cpdef inline
for efficiency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought it was wrong to declare an inline function inside a .pyx that is used in other parts of the code (here in auto_instance.pxi)
It does exist in Cython, which is what matters here. |
The question is: can it happen that |
It is wrong to declare it as inline in a .pxd file. But it's fine to define an inline function in a .pyx file. |
That's not what I meant, but that's actually a good solution too. |
Not |
does not work (at least in Python 3)
|
Removing the
|
I see. This is probably a doctest-specific thing. |
You're right. I though that |
OK, this is a mess but I guess it's the best we can do. For me, there are no further changes needed. |
@defeo do you have any comment? |
@defeo Let say that 6 days mean yes. Though it would be nice to have answered either "do without me" or "wait for me" or whatever... |
I'm sorry. If this is urgent, do without me. When I have time to get back to this, I'll eventually open another ticket if I see any problem. |
This branch is based on top of doctests. I had to make a little hack to make the test pass, namely providing the option
IGNORE_EXCEPTION_DETAIL
to doctest. There is something fishy going on here.