Arrow: Time zone problems with PyInstaller

Created on 22 Aug 2016  路  5Comments  路  Source: arrow-py/arrow

I'm trying to compile a project which uses arrow. It works fine when I run it on the command line. But when I run a Windows executable version compiled by PyInstaller, it fails:

C:\Users{username}\AppData\Local\Temp_MEI180~1\dateutil\zoneinfo__init__.py:38: UserWarning: I/O error(2): No such file or directory

This is followed by a parser error, presumably related to its inability to open the dateutil init:

Traceback (most recent call last):
File "", line 524, in
File "", line 473, in getSkeds
File "", line 387, in parseSchedule
File "site-packages\arrow\arrow.py", line 462, in to
File "site-packages\arrow\parser.py", line 303, in parse
ParserError: (u'Could not parse timezone expression "{0}"', 'US/Central')

I create the executable using this syntax:

pyinstaller scriptname.py --onefile

bug unconfirmed question

Most helpful comment

Surprisingly, removing my pip-installed dateutil and replacing it with an easy_installed dateutil fixed the problem. As suggested here: http://stackoverflow.com/a/16388845/566307

All 5 comments

FWIW, according to pip, I have arrow v0.8.0 and dateutil v2.5.3.

I traced the problem to line 1293 of dateutil/tz.py:
from dateutil.zoneinfo import gettz
This works in local mode, but fails when compiled into a Windows executable.

Surprisingly, removing my pip-installed dateutil and replacing it with an easy_installed dateutil fixed the problem. As suggested here: http://stackoverflow.com/a/16388845/566307

Very odd. Glad you were able to work around it.

Apologies for necroing this issue, but I've run into this exact situation except I'm on Windows so the easy_installed workaround doesn't help me. I'm posting this solution in case some other poor soul runs up against this.

I've traced back the issue to PyInstaller not including the dateutil.zoneinfo.dateutil-zoneinfo.tar.gz reference information during packaging. When accessed, the getzoneinfofile_stream method cannot find the packaged file and doesn't load the time zones. Then you end up with errors parsing time zones because there are no defined zones.

The workaround is to:

  1. bundle the dateutil-zoneinfo.tar.gz file as a data source in your installer (i.e. adding ('\Path\To\site-packages\dateutil\zoneinfo\dateutil-zoneinfo.tar.gz', '.')
  2. create a loader method which points to this data file
  3. replace the dateutil.zoneinfo.getzoneinfofile_stream method with this method

Then when the method is accessed by your code, the auto-constructor references the source data you bundled. It's hacky but it appears to work. I initially tried to pre-construct the ZoneInfo instance, but that wasn't associated with the get_zonefile_instance cache so it wasn't referenced when the code tried to parse a time zone.

Here's the code I used for a workaround:

import sys
import pathlib

# data path reference for script and packaged versions (the default '' lets this work in script-mode) 
data_path = getattr(sys, '_MEIPASS', '')  # _MEIPASS is the path referenced by the executable created by PyInstaller 


def override_getzoneinfofile_stream():
    """
    method for overriding the dateutil.zoneinfo building method

    Assign this to method dateutil.zoneinfo.getzoneinfofile_stream and the ZoneInfo contructor will retrieve the
    information it points to.
    """
    with open(pathlib.Path(data_path, 'dateutil-zoneinfo.tar.gz'), 'rb') as f:
        payload = f.read()
    return BytesIO(payload)


# if there is packaged dateutil info
if pathlib.Path(data_path if data_path != __name__ else '', 'dateutil-zoneinfo.tar.gz').is_file():
    script_logger.info('overriding time zone reference file retrieval')
    import dateutil.zoneinfo
    # override bytes retrieval method
    dateutil.zoneinfo.getzoneinfofile_stream = override_getzoneinfofile_stream

In terms of whether this is a bug, it's a pretty specific use case so no, but _geeze_ was it difficult to override the loading behaviour. It would have been much easier if there was some way to build the time zone defaults from a user-provided file. So the issue lies on the dateutil side, but maybe there could be some way for arrow to implement something which allows user timezone definition.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jadchaar picture jadchaar  路  7Comments

andrewmwilson picture andrewmwilson  路  7Comments

fbergero picture fbergero  路  4Comments

mtrahan picture mtrahan  路  7Comments

rotten picture rotten  路  4Comments