Discussion:
bugs in 2to3 tools when porting sympy
Ondrej Certik
2009-07-05 22:22:04 UTC
Permalink
Received: from localhost.localdomain (HELO mail.python.org) (127.0.0.1)
by albatross.python.org with SMTP; 06 Jul 2009 00:22:05 +0200
X-policyd-weight: using cached result; rate: -8.4
Received: from mail-yx0-f178.google.com (mail-yx0-f178.google.com
[209.85.210.178]) by mail.python.org (Postfix) with ESMTP
for <python-porting-+ZN9ApsXKcEdnm+***@public.gmane.org>; Mon, 6 Jul 2009 00:22:05 +0200 (CEST)
Received: by yxe8 with SMTP id 8so5511951yxe.9
for <python-porting-+ZN9ApsXKcEdnm+***@public.gmane.org>; Sun, 05 Jul 2009 15:22:04 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma;
h=domainkey-signature:mime-version:sender:received:date
:x-google-sender-auth:message-id:subject:from:to:content-type
:content-transfer-encoding;
bh=0YuZ1agkX4dnFp6nLRqiosYzJ60efDUcBxvgBJ5k7UY=;
b=Zg6Hv9zsjBHF/qujGlU1gxfdUOQ5vMmTl2CjAcjC1sledWNtqT+VaTRSmypY5uMTRE
HnDGs0B+aQDkaRnYHxUXnq60sA5BYQLnUZxOYjwfGuICCRSGuO8lI4wKhhQ+DTCOJRqt
ysoFjok2rueFCJJXUps8s53vSYrtlwEzi/Ou0=
DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma;
h=mime-version:sender:date:x-google-sender-auth:message-id:subject
:from:to:content-type:content-transfer-encoding;
b=x98qAc4bCEx25HWjw8V2cLvCbCZyR+NOscKU9Lw/r3UmFA+dubl36qVFnfcG+LrU25
7G3IhdQmVMGZo66ynvVswlsF32jc3AoZypUPRIW68k+hSscv4/squVtvAoJUWr6Oim92
fnsPzqEt/dAGzDtFpo9e+Ws9cy+Ao2kpgda80=
Received: by 10.90.69.7 with SMTP id r7mr3490795aga.47.1246832524669; Sun, 05
Jul 2009 15:22:04 -0700 (PDT)
X-Google-Sender-Auth: 6832b25d45f39da3
X-BeenThere: python-porting-+ZN9ApsXKcEdnm+***@public.gmane.org
X-Mailman-Version: 2.1.12
Precedence: list
List-Id: "Discussion about porting Python code \(mainly 2.x -> 3.x\)"
<python-porting.python.org>
List-Unsubscribe: <http://mail.python.org/mailman/options/python-porting>,
<mailto:python-porting-request-+ZN9ApsXKcEdnm+***@public.gmane.org?subject=unsubscribe>
List-Archive: <http://mail.python.org/pipermail/python-porting>
List-Post: <mailto:python-porting-+ZN9ApsXKcEdnm+***@public.gmane.org>
List-Help: <mailto:python-porting-request-+ZN9ApsXKcEdnm+***@public.gmane.org?subject=help>
List-Subscribe: <http://mail.python.org/mailman/listinfo/python-porting>,
<mailto:python-porting-request-+ZN9ApsXKcEdnm+***@public.gmane.org?subject=subscribe>
Sender: python-porting-bounces+gcpp-python-porting=m.gmane.org-+ZN9ApsXKcEdnm+***@public.gmane.org
Errors-To: python-porting-bounces+gcpp-python-porting=m.gmane.org-+ZN9ApsXKcEdnm+***@public.gmane.org
Archived-At: <http://permalink.gmane.org/gmane.comp.python.porting/41>

Hi,

here is a list of bugs that are triggered by running the 2to3 tool on
sympy, together with steps how to reproduce them. I am running 2to3
tool from python3.1. I created a "2to3-bugs" branch on my github
account with sympy and I am going to leave that branch there without
further modificaitons, so that you can easily debug it anytime.

1) fails with unicode:

$ git clone git://github.com/certik/sympy.git
$ cd sympy
$ git checkout -b 2to3-bugs origin/2to3-bugs
$ 2to3 . > p
RefactoringTool: Skipping implicit fixer: buffer
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: set_literal
RefactoringTool: Skipping implicit fixer: ws_comma
RefactoringTool: Can't parse ./data/IPython/ipythonrc-sympy:
ParseError: bad input: type=1, value='ipythonrc', context=(' ', (25,
8))
RefactoringTool: Can't parse
./doc/src/modules/galgebra/GA/BasicGAtest.py: ParseError: bad input:
type=5, value=' ', context=('', (1, 0))
RefactoringTool: Can't parse
./doc/src/modules/galgebra/GA/conformalgeometryGAtest.py: ParseError:
bad input: type=5, value=' ', context=('', (1, 0))
RefactoringTool: Can't parse
./doc/src/modules/galgebra/GA/headerGAtest.py: ParseError: bad input:
type=0, value='', context=('\n', (26, 0))
RefactoringTool: Can't parse
./doc/src/modules/galgebra/GA/hyperbolicGAtest.py: ParseError: bad
input: type=5, value=' ', context=('', (1, 0))
RefactoringTool: Can't parse
./doc/src/modules/galgebra/GA/reciprocalframeGAtest.py: ParseError:
bad input: type=5, value=' ', context=('', (1, 0))
Traceback (most recent call last):
File "/home/ondrej/ext/Python-3.1/Tools/scripts/2to3", line 6, in <module>
sys.exit(main("lib2to3.fixes"))
File "/home/ondrej/ext/Python-3.1/Lib/lib2to3/main.py", line 132, in main
options.processes)
File "/home/ondrej/ext/Python-3.1/Lib/lib2to3/refactor.py", line
544, in refactor
items, write, doctests_only)
File "/home/ondrej/ext/Python-3.1/Lib/lib2to3/refactor.py", line
207, in refactor
self.refactor_dir(dir_or_file, write, doctests_only)
File "/home/ondrej/ext/Python-3.1/Lib/lib2to3/refactor.py", line
225, in refactor_dir
self.refactor_file(fullname, write, doctests_only)
File "/home/ondrej/ext/Python-3.1/Lib/lib2to3/refactor.py", line
584, in refactor_file
*args, **kwargs)
File "/home/ondrej/ext/Python-3.1/Lib/lib2to3/refactor.py", line
264, in refactor_file
write=write, encoding=encoding)
File "/home/ondrej/ext/Python-3.1/Lib/lib2to3/refactor.py", line
363, in processed_file
self.print_output(diff_texts(old_text, new_text, filename))
File "/home/ondrej/ext/Python-3.1/Lib/lib2to3/main.py", line 47, in
print_output
print(line)
UnicodeEncodeError: 'ascii' codec can't encode character '\u03b1' in
position 32: ordinal not in range(128)


this was already reported here: http://bugs.python.org/issue5093

it also reports the "RefactoringTool: Can't parse" errors, I don't
know what that means.

2) It doesn't fix all imports:

$ git clone git://github.com/certik/sympy.git
$ cd sympy
$ git checkout -b 2to3-bugs origin/2to3-bugs
$ 2to3 -w . # this is necessary due to the bug 1)

now if you look into the sympy/__init__.py file, you need to apply the
following patch:

-from series import *
-from functions import *
-from ntheory import *
-from concrete import *
-from simplify import *
-from solvers import *
-from matrices import *
-from geometry import *
-from utilities import *
-from integrals import *
+from .series import *
+from .functions import *
+from .ntheory import *
+from .concrete import *
+from .simplify import *
+from .solvers import *
+from .matrices import *
+from .geometry import *
+from .utilities import *
+from .integrals import *


the same about most of other __init__.py files in sympy. I believe
this is a bug in 2to3 tool, that should do it automatically.

3) there is a file sympy/printing/repr.py which is imported in
sympy/printing/__init__.py. For some reason the 2to3 tool produces a
patch:

-from repr import srepr
+from reprlib import srepr

however the correct patch is:

-from repr import srepr
+from .repr import srepr

I think 2to3 tool should first check if a local file is present and if
so, treat this as a local import, not a std library import.


Besides the 3 bugs above, there are lots of small annoyances, like
that sys.version_info has changed, so one has to use tuple() around
it, that .sort() doesn't accept a cmp() like callback anymore, and
similar things, which hopefully should be relatively easy to fix in a
manner that works in all pythons.

Then there is a big problem that for some reason, hash() doesn't work
on our Integer class anymore, but seems to work on some other classes.
After I fixed the above errors by hand, here is a result of our test
suite (and this is only sympy/core, e.g. about 1/10 of all our
tests...):

http://groups.google.com/group/sympy/msg/525e8420ebb2b08d

so it is now clear that it will be a lot of work to port everything.
But I still believe it would be possible to just maintain one
codebase, and run 2to3 tool to produce python3 compatible library.

If anyone could give me some help with the bugs in 2to3 tool, it'd be
awesome, it would simplify our job a lot. Otherwise we would have to
create some specialized scripts to convert the rest of sympy (after
the 2to3 tool run) to be python3 compatible.

Ondrej
Benjamin Peterson
2009-07-06 00:21:03 UTC
Permalink
Could you try with the latest version of 2to3 from the sandbox? [1]
I've recently fixed I think all of the bugs you've described.

[1] http://svn.python.org/projects/sandbox/trunk/2to3
Post by Ondrej Certik
Besides the 3 bugs above, there are lots of small annoyances, like
that sys.version_info has changed, so one has to use tuple() around
it, that .sort() doesn't accept a cmp() like callback anymore, and
similar things, which hopefully should be relatively easy to fix in a
manner that works in all pythons.
What are you doing with sys.version_info which makes it incompatible?
--
Regards,
Benjamin
Ondrej Certik
2009-07-06 00:54:46 UTC
Permalink
Post by Benjamin Peterson
Could you try with the latest version of 2to3 from the sandbox? [1]
I've recently fixed I think all of the bugs you've described.
I tested the bug 1):

$ python2.6 ~/repos/2to3/2to3 . > p
WARNING: not writing files and not printing diffs; that's not very useful
root: Generating grammar tables from
/home/ondrej/repos/2to3/lib2to3/PatternGrammar.txt
root: Writing grammar tables to
/home/ondrej/repos/2to3/lib2to3/PatternGrammar2.6.2.final.0.pickle
RefactoringTool: Skipping implicit fixer: buffer
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: set_literal
RefactoringTool: Skipping implicit fixer: ws_comma
RefactoringTool: Refactored ./setup.py
RefactoringTool: Refactored ./setupegg.py
RefactoringTool: Refactored ./bin/adapt_paths.py
RefactoringTool: Refactored ./bin/coverage_report.py
RefactoringTool: Refactored ./bin/generate_test_list.py
RefactoringTool: Refactored ./bin/isympy
RefactoringTool: Refactored ./bin/sympy_time.py
RefactoringTool: Refactored ./bin/sympy_time_cache.py
RefactoringTool: Refactored ./bin/test_import.py
RefactoringTool: Can't parse ./data/IPython/ipythonrc-sympy:
ParseError: bad input: type=1, value=u'ipythonrc', context=(u' ', (25,
8))
RefactoringTool: Refactored ./doc/generate_reference.py
RefactoringTool: Can't parse
./doc/src/modules/galgebra/GA/BasicGAtest.py: ParseError: bad input:
type=5, value=u' ', context=(u'', (1, 0))
RefactoringTool: Refactored ./doc/src/modules/galgebra/GA/Dirac.py
RefactoringTool: Refactored ./doc/src/modules/galgebra/GA/Maxwell.py
RefactoringTool: Can't parse
./doc/src/modules/galgebra/GA/conformalgeometryGAtest.py: ParseError:
bad input: type=5, value=u' ', context=(u'', (1, 0))
RefactoringTool: Refactored ./doc/src/modules/galgebra/GA/coords.py
RefactoringTool: Can't parse
./doc/src/modules/galgebra/GA/headerGAtest.py: ParseError: bad input:
type=0, value='', context=(u'\n', (26, 0))
RefactoringTool: Can't parse
./doc/src/modules/galgebra/GA/hyperbolicGAtest.py: ParseError: bad
input: type=5, value=u' ', context=(u'', (1, 0))
RefactoringTool: Can't parse
./doc/src/modules/galgebra/GA/reciprocalframeGAtest.py: ParseError:
bad input: type=5, value=u' ', context=(u'', (1, 0))
RefactoringTool: Refactored ./doc/src/modules/galgebra/latex_ex/Maxwell.py
RefactoringTool: Refactored ./doc/src/modules/galgebra/latex_ex/latexdemo.py
RefactoringTool: Refactored ./examples/all.py
RefactoringTool: Refactored ./examples/advanced/curvilinear_coordinates.py
RefactoringTool: Refactored ./examples/advanced/fem.py
RefactoringTool: Refactored ./examples/advanced/gibbs_phenomenon.py
RefactoringTool: Refactored ./examples/advanced/pidigits.py
RefactoringTool: Refactored ./examples/advanced/plotting.py
RefactoringTool: Refactored ./examples/advanced/qft.py
RefactoringTool: Refactored ./examples/advanced/relativity.py
RefactoringTool: Refactored ./examples/beginner/basic.py
RefactoringTool: Refactored ./examples/beginner/differentiation.py
RefactoringTool: Refactored ./examples/beginner/expansion.py
RefactoringTool: Refactored ./examples/beginner/functions.py
RefactoringTool: Refactored ./examples/beginner/limits_examples.py
RefactoringTool: Refactored ./examples/beginner/precision.py
RefactoringTool: Refactored ./examples/beginner/print_pretty.py
RefactoringTool: Refactored ./examples/beginner/series.py
RefactoringTool: Refactored ./examples/beginner/substitution.py
RefactoringTool: Refactored ./examples/intermediate/differential_equations.py
RefactoringTool: No changes to ./examples/intermediate/mplot2d.py
RefactoringTool: Refactored ./examples/intermediate/trees.py
RefactoringTool: Refactored ./examples/intermediate/vandermonde.py
RefactoringTool: Refactored ./sympy/__init__.py
RefactoringTool: Refactored ./sympy/abc.py
RefactoringTool: Refactored ./sympy/benchmarks/bench_symbench.py
RefactoringTool: Refactored ./sympy/concrete/__init__.py
RefactoringTool: Refactored ./sympy/concrete/gosper.py
RefactoringTool: Refactored ./sympy/concrete/products.py
RefactoringTool: Refactored ./sympy/concrete/summations.py
RefactoringTool: Refactored ./sympy/concrete/sums_products.py
RefactoringTool: Refactored ./sympy/concrete/tests/test_sums_products.py
RefactoringTool: Refactored ./sympy/core/__init__.py
RefactoringTool: Refactored ./sympy/core/add.py
RefactoringTool: Refactored ./sympy/core/assumptions.py
RefactoringTool: Refactored ./sympy/core/ast_parser.py
RefactoringTool: Refactored ./sympy/core/ast_parser_python24.py
RefactoringTool: Refactored ./sympy/core/basic.py
RefactoringTool: Refactored ./sympy/core/cache.py
RefactoringTool: Refactored ./sympy/core/decorators.py
RefactoringTool: Refactored ./sympy/core/evalf.py
Traceback (most recent call last):
File "/home/ondrej/repos/2to3/2to3", line 5, in <module>
sys.exit(main("lib2to3.fixes"))
File "/home/ondrej/repos/2to3/lib2to3/main.py", line 157, in main
options.processes)
File "/home/ondrej/repos/2to3/lib2to3/refactor.py", line 545, in refactor
items, write, doctests_only)
File "/home/ondrej/repos/2to3/lib2to3/refactor.py", line 207, in refactor
self.refactor_dir(dir_or_file, write, doctests_only)
File "/home/ondrej/repos/2to3/lib2to3/refactor.py", line 225, in refactor_dir
self.refactor_file(fullname, write, doctests_only)
File "/home/ondrej/repos/2to3/lib2to3/refactor.py", line 585, in refactor_file
*args, **kwargs)
File "/home/ondrej/repos/2to3/lib2to3/refactor.py", line 260, in refactor_file
tree = self.refactor_string(input, filename)
File "/home/ondrej/repos/2to3/lib2to3/refactor.py", line 286, in
refactor_string
self.refactor_tree(tree, name)
File "/home/ondrej/repos/2to3/lib2to3/refactor.py", line 320, in refactor_tree
self.traverse_by(self.post_order_heads, tree.post_order())
File "/home/ondrej/repos/2to3/lib2to3/refactor.py", line 346, in traverse_by
str(new) != str(node)):
File "/home/ondrej/repos/2to3/lib2to3/pytree.py", line 226, in __str__
return unicode(self).encode("ascii")
UnicodeEncodeError: 'ascii' codec can't encode character u'\u03b1' in
position 1248: ordinal not in range(128)



am I invoking it in the correct way? I just downloaded the svn
repository into ~/repos/2to3/.

I cannot easily test bug 2), because even this fails with the
UnicodeEncodeError:

python2.6 ~/repos/2to3/2to3 -w .
Post by Benjamin Peterson
[1] http://svn.python.org/projects/sandbox/trunk/2to3
Post by Ondrej Certik
Besides the 3 bugs above, there are lots of small annoyances, like
that sys.version_info has changed, so one has to use tuple() around
it, that .sort() doesn't accept a cmp() like callback anymore, and
similar things, which hopefully should be relatively easy to fix in a
manner that works in all pythons.
What are you doing with sys.version_info which makes it incompatible?
I had to apply this patch:

v = sys.version_info
- python_version = "%s.%s.%s-%s-%s" % v
+ python_version = "%s.%s.%s-%s-%s" % tuple(v)


the "-" line works in python3.0 and below, but stops working in
python3.1. The fix is trivial, let's not loose time with it. After
fixing the 2to3 tool, I have a serious problem that the __hash__
method is defined in the Basic() class, but in it's subclasses (Number
and Symbol):

Number.__hash__

returns None, but

Symbol.__hash__

correctly points to the Basic.hash method. As a result, Number is not
hashable and this breaks sympy. I already spent 2 hours debugging it,
so far the only clue is that __slots__ influence it, but so far I
wasn't able to isolate a simple failing testcase (if I create a simple
class hierarchy, it works in python3.1), the problem is that it's not
easy to delete just part of sympy -- it's either all or nothing, and
thus it's very difficult to figure out why python3 behaves as it
behaves.

If anyone on this list has experience with debugging such kind of a
problem in python 3, I would be interested in any input.

Ondrej
Ondrej Certik
2009-07-06 01:36:13 UTC
Permalink
On Sun, Jul 5, 2009 at 6:54 PM, Ondrej Certik<ondrej-***@public.gmane.org> wrote:
[...]
Post by Ondrej Certik
I have a serious problem that the __hash__
method is defined in the Basic() class, but in it's subclasses (Number
Number.__hash__
returns None, but
Symbol.__hash__
correctly points to the Basic.hash method. As a result, Number is not
hashable and this breaks sympy. I already spent 2 hours debugging it,
so far the only clue is that __slots__ influence it, but so far I
wasn't able to isolate a simple failing testcase (if I create a simple
class hierarchy, it works in python3.1), the problem is that it's not
easy to delete just part of sympy -- it's either all or nothing, and
thus it's very difficult to figure out why python3 behaves as it
behaves.
If anyone on this list has experience with debugging such kind of a
problem in python 3, I would be interested in any input.
Here is how to reproduce it:

$ git clone git://github.com/certik/sympy.git
$ cd sympy
$ git checkout -b py3-hash-bug origin/py3-hash-bug
$ SYMPY_USE_CACHE=no python3.1 t.py
1
2
Atom: <function __hash__ at 0x1c0c270>
Number: None
Integer: None
Symbol: <function __hash__ at 0x1c0c270>

as you can see, the __hash__ method is defined in Basic and all Atom,
Number, Integer and Symbol are subclasses of Basic.

I must say I am totally puzzled as how this is possible.

Ondrej

P.S. The "SYMPY_USE_CACHE=no" is necessary, because otherwise sympy
will not import (due to this hash bug), as it can't cash things.
Amaury Forgeot d'Arc
2009-07-06 08:01:19 UTC
Permalink
Hello,
[...]
Post by Ondrej Certik
I have a serious problem that the __hash__
method is defined in the Basic() class, but in it's subclasses (Number
Number.__hash__
returns None, but
Symbol.__hash__
correctly points to the Basic.hash method.
Number certainly defines a __eq__ method, which blocks the inheritance
of __hash__.
See the last paragraph of
http://docs.python.org/dev/py3k/reference/datamodel.html#object.__hash__
--
Amaury Forgeot d'Arc
Ondrej Certik
2009-07-06 09:14:40 UTC
Permalink
Post by Amaury Forgeot d'Arc
Hello,
[...]
Post by Ondrej Certik
I have a serious problem that the __hash__
method is defined in the Basic() class, but in it's subclasses (Number
Number.__hash__
returns None, but
Symbol.__hash__
correctly points to the Basic.hash method.
Number certainly defines a __eq__ method, which blocks the inheritance
of __hash__.
See the last paragraph of
http://docs.python.org/dev/py3k/reference/datamodel.html#object.__hash__
That was it! Many thanks for the hint, without it I would spend a lot
more hours on this.
So Python3.0 seems to be more strict than python2.6, since that code
is in sympy for a long time and it always worked in python2.4 up to
2.6. The fix is trivial, I just assign the __hash__ method from a
parent and things start working.

There are other unrelated failures, but those I will tackle myself.

Thanks again for the help,
Ondrej
Benjamin Peterson
2009-07-11 21:45:55 UTC
Permalink
Post by Benjamin Peterson
Could you try with the latest version of 2to3 from the sandbox? [1]
I've recently fixed I think all of the bugs you've described.
Ok. Thank you. You discovered several more bugs. Please try again with
my latest fixes.
--
Regards,
Benjamin
Loading...