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
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:
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', '.')dateutil.zoneinfo.getzoneinfofile_stream method with this methodThen 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.
Most helpful comment
Surprisingly, removing my pip-installed
dateutiland replacing it with an easy_installed dateutil fixed the problem. As suggested here: http://stackoverflow.com/a/16388845/566307