The*_*Guy 10 python pyinstaller pandas parquet pyarrow
请考虑以下程序作为最小可重现示例 -MRE:
import pandas as pd
import pyarrow
from pyarrow import parquet
def foo():
print(pyarrow.__file__)
print('version:',pyarrow.cpp_version)
print('-----------------------------------------------------')
df = pd.DataFrame({'A': [1,2,3], 'B':['dummy']*3})
print('Orignal DataFrame:\n', df)
print('-----------------------------------------------------')
_table = pyarrow.Table.from_pandas(df)
parquet.write_table(_table, 'foo')
_table = parquet.read_table('foo', columns=[]) #passing empty list to columns arg
df = _table.to_pandas()
print('After reading from file with columns=[]:\n', df)
print('-----------------------------------------------------')
print('Not passing [] to columns parameter')
_table = parquet.read_table('foo') #Not passing any list
df = _table.to_pandas()
print(df)
print('-----------------------------------------------------')
x = input('press any key to exit: ')
if __name__=='__main__':
foo()
Run Code Online (Sandbox Code Playgroud)
当我从控制台/IDE 运行它时,它会读取以下所有数据columns=[]:
(env) D:\foo>python foo.py
D:\foo\env\lib\site-packages\pyarrow\__init__.py
version: 3.0.0
-----------------------------------------------------
Orignal DataFrame:
A B
0 1 dummy
1 2 dummy
2 3 dummy
-----------------------------------------------------
After reading from file with columns=[]:
A B
0 1 dummy
1 2 dummy
2 3 dummy
-----------------------------------------------------
Not passing [] to columns parameter
A B
0 1 dummy
1 2 dummy
2 3 dummy
-----------------------------------------------------
press any key to exit:
Run Code Online (Sandbox Code Playgroud)
但是当我从使用 Pyinstaller 创建的可执行文件运行它时,它没有读取以下数据columns=[]:
E:\foo\dist\foo\pyarrow\__init__.pyc
version: 3.0.0
-----------------------------------------------------
Orignal DataFrame:
A B
0 1 dummy
1 2 dummy
2 3 dummy
-----------------------------------------------------
After reading from file with columns=[]:
Empty DataFrame
Columns: []
Index: [0, 1, 2]
-----------------------------------------------------
Not passing [] to columns parameter
A B
0 1 dummy
1 2 dummy
2 3 dummy
-----------------------------------------------------
press any key to exit:
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,传递columns=[]在可执行文件中给出了空数据帧,但是在直接运行 python 文件时这种行为不存在,而且我不确定为什么在同一环境中对同一代码有这两种不同的行为。
综观文档字符串parquet.read_table中在GitHub的源代码:
columns: list
如果不是 None,则只会从文件中读取这些列。列名可以是嵌套字段的前缀,例如“a”将选择“a.b”、“a.c”和“ade”。
该read_table进一步呼叫dataset.read的呼叫_dataset.to_table返回调用self.scanner,然后返回调用静态方法from_dataset的Scanner类。
无处不在,None一直被用作columns参数的默认值,如果None和[]在python中直接转换为布尔值,两者确实会是False,但如果[]是检查None,那么会是False,但没有提到它是否应该获取所有列对于columns=[]因为它的计算结果是False布尔值,或因为该列表是空的应该它在所有阅读没有列。
但是,为什么从命令行/IDE 运行它时的行为与从使用 Pyinstaller 为相同版本的 Pyarrow 创建的可执行文件运行它时的行为不同?
我所在的环境:
如果您想尝试一下,这里是您参考的规范文件(您需要更改pathex参数):
foo.spec
# -*- mode: python ; coding: utf-8 -*-
import sys ; sys.setrecursionlimit(sys.getrecursionlimit() * 5)
block_cipher = None
a = Analysis(['foo.py'],
pathex=['D:\\foo'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='foo',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='foo')
Run Code Online (Sandbox Code Playgroud)
感谢 @U12-Forward 帮助我调试问题。
经过一番研究和调试,并探索了库程序文件,我发现 pyarrow 的 use_ParquetDatasetV2和ParquetDatasetfunction 本质上是两个不同的函数,它们从 parquet 文件中读取数据,_ParquetDatasetV2被用作legacy_mode,即使这些函数是在 pyarrow.parquet 中定义的模块,它们来自Datasetpyarrow 模块,该模块在使用 Pyinstaller 创建的可执行文件中缺失。
当我添加为隐藏导入并创建构建时,由于模块使用的几个缺少的依赖项,pyarrow.Datasetexe 在执行时会引发异常。为了解决这个问题,我将环境中的所有文件添加到隐藏导入中,并再次创建构建,最后它起作用了,我的意思是我能够在两个环境中观察到相同的行为。ModuleNotFoundErrorDataset.py
修改后的spec文件如下所示:
# -*- mode: python ; coding: utf-8 -*-
import sys ; sys.setrecursionlimit(sys.getrecursionlimit() * 5)
block_cipher = None
a = Analysis(['foo.py'],
pathex=['D:\\foo'],
binaries=[],
datas=[],
hiddenimports=['pyarrow.benchmark', 'pyarrow.cffi', 'pyarrow.compat', 'pyarrow.compute', 'pyarrow.csv', 'pyarrow.cuda', 'pyarrow.dataset', 'pyarrow.feather', 'pyarrow.filesystem', 'pyarrow.flight', 'pyarrow.fs', 'pyarrow.hdfs', 'pyarrow.ipc', 'pyarrow.json', 'pyarrow.jvm', 'pyarrow.orc', 'pyarrow.pandas_compat', 'pyarrow.parquet', 'pyarrow.plasma', 'pyarrow.serialization', 'pyarrow.types', 'pyarrow.util', 'pyarrow._generated_version', 'pyarrow.__init__'],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='foo',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='foo')
Run Code Online (Sandbox Code Playgroud)
此外,为了创建构建,我使用参数包含了虚拟环境的路径--paths:
pyinstaller --path D:\foo\env\Lib\site-packages foo.spec
Run Code Online (Sandbox Code Playgroud)
这是执行上述步骤后的执行:
E:\foo\dist\foo\pyarrow\__init__.pyc
version: 3.0.0
-----------------------------------------------------
Orignal DataFrame:
A B
0 1 dummy
1 2 dummy
2 3 dummy
-----------------------------------------------------
After reading from file with columns=[]:
A B
0 1 dummy
1 2 dummy
2 3 dummy
-----------------------------------------------------
Not passing [] to columns parameter
A B
0 1 dummy
1 2 dummy
2 3 dummy
-----------------------------------------------------
press any key to exit:
Run Code Online (Sandbox Code Playgroud)
确实,没有任何地方提到 的期望行为columns=[],但是看看@Pace在 pyarrow 中打开的 ARROW-13436,似乎 的期望行为columns=[]是根本不读取任何数据列,但它不是官方的构造,所以这可能是 pyarrow 3.0.0 本身的一个错误。