Support both Python 2 and 3

Bug #746550 reported by kumar303
38
This bug affects 8 people
Affects Status Importance Assigned to Milestone
dateutil
Fix Released
Undecided
Tomi Hukkalainen

Bug Description

Hi, it's really confusing that python-dateutil drops support for Python 2 in its new version. What happens is pip install python-dateutil from most old 2.x projects will get the new version automatically and things fail in confusing ways like this:

>>> from dateutil.parser import parse
>>> parse('2011-03-31T15:59:07.440Z')
Traceback (most recent call last):
  ...
  File "/Users/kumar/tmp/dateutil-env/lib/python2.6/site-packages/dateutil/parser.py", line 144, in split
    return list(cls(s))
TypeError: iter() returned non-iterator of type '_timelex'

This is a feature request: please try supporting Python 2 using the 3to2 conversion tool in your setup.py file (or by building a Python 2 egg at deploy time for PyPI).
http://wiki.python.org/moin/3to2
http://jessenoller.com/2009/08/27/python-3to2-go-check-it-out/

I don't know how well 3to2 it works but it's worth a try. You can add Python 2 to your test suite with tox http://codespeak.net/tox/

If 3to2 doesn't work it's probably not so hard to make a single source module. Mock was able to do this with a few hacks: http://www.voidspace.org.uk/python/articles/porting-mock-to-python-3.shtml

Finally, if all else fails, 2to3 is an awesome tool and works very well.

I really feel strongly that you're doing a huge disservice to the community by dropping Python 2 right now; it's too soon. Dateutil is an *essential* library so I praise your efforts on this wonderful tool. I consider it to be one of the missing standard library modules. The reality is that Python 3 adoption is going to be very gradual and I think it's the responsibility of essential module developers to support both versions. Even those who want to port to Python 3 are going to be held back by their dependencies.

thanks, Kumar

Related branches

Revision history for this message
kumar303 (kumar-mcmillan) wrote :

I should add that since I do feel strongly enough about this, I can help work on Python 2 support! I will try to find time for this if no one beats me to it...

Revision history for this message
kumar303 (kumar-mcmillan) wrote :

On a closer look, I see that you didn't actually push 2.0 to PyPI so you might be confused as to why pip finds 2.0. I have a hunch that the setuptools magic link scraper is loading your home page in addition to the PyPI page before deciding which tarball to download. pip is a wrapper around setuptools.

Revision history for this message
Zooko Wilcox-O'Hearn (zooko) wrote :

An alternative to 3to2 would be to use http://packages.python.org/six/

The advantage of that is that you have one codebase which is maintained by humans and there is no autogenerated code.

Revision history for this message
Gustavo Niemeyer (niemeyer) wrote :

There's no need to port or to work in Python 2.X support. dateutil 1.5 works in Python 2, and there are absolutely no extra bug fixes or features in dateutil 2.0 at this point in addition to the Python 3.X support.

If easy_install is installing dateutil 2.0 in Python 2, that's a bug in easy_install which should be fixed there.

I really apologize for the inconvenience.

Changed in dateutil:
status: New → Invalid
Revision history for this message
Min Ragan-Kelley (minrk) wrote :

It's not quite accurate that this is an easy_install bug - it's actually a feature*, albeit an annoying one.

If you specify the download url or homepage, setuptools will also scrape those pages for download links, and select the latest-looking file that matches.

A couple of ways to prevent easy_install from finding links you don't want it to:

* move download links to a secondary downloads page that is not linked directly from PyPI listing (easy_install shouldn't make more than one hop from PyPI)
* don't use names that match the setuptools pattern on files it shouldn't be finding (e.g. python3-dateutil-2.0.tar.gz would not be considered a candidate for 'python-dateutil')

* http://peak.telecommunity.com/DevCenter/EasyInstall#package-index-api (pt #6)

Revision history for this message
Gustavo Niemeyer (niemeyer) wrote :

> It's not quite accurate that this is an easy_install bug - it's actually a feature*, albeit an annoying one.
(...)
> * move download links to a secondary downloads page that is not linked
> * don't use names that match the setuptools pattern on files it shouldn't be

If the application you're using scraps a web page with custom heuristics and screws up,
please complain to the application author that his "feature" is broken, not to the web
page author.

Changed in dateutil:
status: Invalid → In Progress
Revision history for this message
Tomi Hukkalainen (tpievila) wrote :

I'm going to add functionality to dateutil, and need it to work on Python 2. However I don't seen any reason to make the new things work only for Python 2, so I started working on patch on top of the 2.0 that makes it work at least on 2.6-2.7. My approach is using the six package, as that has worked very well for my other projects supporting 2.6-3.2.

I do have some things I'm not quite sure how to implement though, and I'll discuss these in this bug report. First one is how to handle all functions reading data from strings. In 1.5 the tests are with byte strings, but in 2.0 the syntax wasn't changed and thus the type is now unicode. iCalendar RFC says in section 3.1.4. that iCalendars should be encoded in UTF-8, which matches the new functions. However, the parser part of dateutil doesn't refer to the iCalendar spec, unlike rrule.

For now I think I'll just make all strings work like they do in 2.0, thus changing the API somewhat from 1.5. But any comments are appreciated.

Changed in dateutil:
assignee: nobody → Tomi Pieviläinen (tpievila)
summary: - please support Python 2 using 3to2 (or something)
+ Support both Python 2 and 3
Changed in dateutil:
status: In Progress → Fix Committed
Revision history for this message
Taavi Burns (taavi-burns) wrote :

I peeked at the diff and noticed a docstring that isn't (because "import six" happens first):

=== modified file 'dateutil/tz.py'
234 --- dateutil/tz.py 2011-03-24 17:37:46 +0000
235 +++ dateutil/tz.py 2012-02-18 20:49:17 +0000
236 @@ -25,6 +25,20 @@
237 except (ImportError, OSError):
238 tzwin, tzwinlocal = None, None
239
240 +def tzname_in_python2(myfunc):
241 + import six
242 + """Change unicode output into bytestrings in Python 2
243 +
244 + tzname() API changed in Python 3. It used to return bytes, but was changed
245 + to unicode strings
246 + """
247 + def inner_func(*args, **kwargs):
248 + if six.PY3:
249 + return myfunc(*args, **kwargs)
250 + else:
251 + return myfunc(*args, **kwargs).encode()
252 + return inner_func
253 +

Revision history for this message
Tomi Hukkalainen (tpievila) wrote :

Thanks for catching that, it was a pretty dumb mistake. Is that version working fine otherwise?

Changed in dateutil:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.